Linux学习记录——삽심칠 传输层TCP协议(2)

文章目录

  • 1、滑动窗口
  • 2、拥塞控制
  • 3、延迟应答
  • 4、捎带应答
  • 5、总结TCP可靠性和性能提高
  • 6、面向字节流
  • 7、粘包问题
  • 8、异常情况
  • 9、全连接、半连接


上一篇是传输层TCP协议(1)。本篇默认读者已经清楚TCP报头各个部分、可靠性和握手挥手的含义。
有时候会把客户端写作C,服务端写作S。

1、滑动窗口

C和S之间的交互有串行的方案,一收一发;多发多收,时间会有重叠,效率更高,这是TCP通信的主流方案。对于TCP,可靠性确实重要,但效率也是其考虑的重点。发不能超过收的上限,在能收的前提下再发。一次最大发送量取决于对方窗口大小。发送方和接收方可以互换角色。

窗口大小在发送方的发送缓冲区内,滑动窗口是发送缓冲区的一部分,这部分可以不用收到应答,直接发送,当然也得对方能收得了。这样可以把发送缓冲区分成三部分,左边部分是已经确认发送了的,这部分可以被覆盖;中间是滑动窗口部分,可以直接发送但尚未收到应答;右边部分是尚未发送的数据。中间部分一旦有数据收到应答,窗口就滑动,向右滑动。滑动窗口有多大取决于对方发送的应答报文中的窗口大小。当应用层有数据写入时,比如调用write函数,就会把数据放到右边的部分。

假设把发送缓冲区当作一个char数组,因为char能访问1字节的数据,数组分出多个块。发送数据,缓冲区接收,这也就是流的概念。每个进来的数据都有下标作为序号。滑动窗口就是两个下标之间的区间,假设下标是start和end,当创窗口开始移动时,就是前后下标+±-。

在这里插入图片描述

滑动窗口不能向左滑动,因为左边是已经发送且确认的,右边是没发送的。滑动窗口取决于对方的接收能力,所以可以变大变小,变大就是end += …,变小就是start += …,变0就是对方接收缓冲区满了,两个指针指向同一个位置。

发送要按序,应答也会按序。应答报文中有两个重要字段,序号和窗口大小。序号表示这个序号之前的报文都收到了,所以start = 序号,应答报文的窗口大小win,则对应着end = start + win。应答报文不断发送,start就不断更新,以win变化或者不变化,end都向右移动,这样窗口就滑动了。

假设发送了100,200,300,400报文,如果第一个丢失,怎么办?丢失有两种情况,一个是发送出去了,而对方的ACK,也就是应答丢失了,这个没有关系,因为后续收到201报文,其实就知道100报文丢了,但能根据201报文调整窗口;另一个情况是还没发送出去,数据丢了,而不是应答丢失,比如中间的200报文没发送过去,100,300,400都收到了,这时候服务器即使收到了后面几个报文,返回的几个应答中的序号也都会写101,客户端得到重复的101后,TCP就知道丢包了,此时客户端就等待超时重传,重新发200报文,这个机制叫做高速重发或者快重传机制。而为了超时重传,为了数据没丢,服务器确认收到之前,报文都必须先保存,这里就对应上窗口根本没动,数据保存在滑动窗口,加上之前收到300,400报文,200重发后,服务器就会发送序号为401的应答,客户端就从400报文往后继续发。

无论窗口内哪个位置的报文丢包了,都不需要担心,办法就是上段所说。

窗口一直滑动,也不会越界,因为发送缓冲区可以设计成环状结构,就可以做到循环使用。这也就是为什么数据可以被覆盖。所以这里就用到了环形队列。

快重传和超时重传不冲突,共存,快重传决定重传的上限,超时重传决定重传下限。

2、拥塞控制

客户端C和服务端S之间的交互,C会发送数据到网络中,S会从网络中拿到数据,C和S不仅有各种机制,网络也有机制。网络相比于C和S复杂得多。网络里有大量发送方和接收方,网络中所有的主机或设备都在遵守TCP/IP协议。

出现错误,出现的次数多和出现的次数少的原因是不同的,比如丢包,丢的少可能是发送方问题,丢的多可能就是网络问题。当出现大量丢包时,这个问题就是网络拥塞,此时重传会加重网络负担,因为网络内所有主机都会被影响,主机都会判定网络出现拥塞,然后在短时间内大量重发数据,就会加重网络负担,加重拥塞问题。所以重传的机制都不能采用。

拥塞的原因有很多,TCP只是网络策略,没办法彻底解决网络的大部分问题。网络拥塞的解决也不能让所有的主机都等待处理,这样效率有点低。在网络拥塞有起色的情况下,要尽快恢复网络通信。

虽然有流量控制,可以尽量减少网络拥塞,但总归还是有,比如最一开始发送数据的时候。当出现网络拥塞后,拥塞控制就开始生效。TCP会先使用慢启动机制,属于拥塞控制机制,发送少量的数据探路,摸清当前拥塞状况,再决定以多少速度来传输数据。比如发一个报文,有应答就发送2个报文,有应答就发送4个报文,以此类推,发送到那个报文丢包了,就知道当前拥塞程度;如果1个报文就丢了,那就说明拥塞很严重。TCP丢包后会超时重传,还是发送丢包前发送的微量报文,等待时间就是为了等网络拥塞好转。

为了衡量网络健康状态,即拥塞状况,用拥塞窗口来当作指标。网络的状态是变化的,那么拥塞窗口大小一定也是变化的。主机要了解网络健康状态只能尝试、探测,也就是得到当前网络的拥塞窗口。发送开始的时候,定义拥塞窗口大小为1,每次收到一个ACK应答,拥塞窗口大小就加1。上面所写的滑动窗口,不仅要对端主机的接收能力,还要看网络的拥塞窗口,所以实际上滑动窗口的上限等于这两个的较小值,用min函数,对应到start和end变量,start还是序号,end则是序号 + 窗口大小,和拥塞窗口的较小值。

拥塞窗口的增长速度是指数级别的,也就是上面所说的发1个,2个,4个,8个。指数增长前期慢,后期飞速增长,这就对应着,试探网络情况时要发少量的报文,后面网络好转了就要尽快恢复正常发送。但指数增长不能一直增长下去,这里就用一个叫做慢启动,也叫ssthreah的阈值,超过阈值就变成线性增长。指数增长到线性增长的整个过程,一直在探测拥塞窗口。当增长超过一次拥塞窗口时,就直接从1开始,重新指数增长,而这一次的阈值变为上一次拥塞窗口的一半,之后不断进行同样的做法。这样的循环会一直循环下去。

3、延迟应答

为了让发送和接收的效率提高,接收方可以给发送方更大的窗口大小。虽然滑动窗口大小还有拥塞窗口在制衡,但如果不给更大的,发送方就不可能在同一时间发送更多的数据,给更大的窗口大小才有这个概率。接收方要给,就得自身接收缓冲区剩余空间更大才行,接收缓冲区的清理取决于上层应用层,要想让应用层更快地读取数据,可以不需要立马应答,发送方还有超时重传机制,在未超时前,接收方等待一下,给应用层更多时间,让应用层多读取一些数据再给应答,这就是延迟应答。

延迟应答可以利用时间等待来应答,也可以每隔几个包再应答一次。一般每隔2个包,或者等待不超过200ms。

4、捎带应答

这个在之前的博客中写过,也就是一次性多发几个报文,不占用效率反而提高效率。有些报文不需要单独发一次,所以就在发送一个报文时,顺便带上这些报文。

5、总结TCP可靠性和性能提高

可靠性:

检验和(校验和),序列号,确认应答,超时重发,连接管理,流量控制,拥塞控制

提高性能:

滑动窗口,快速重传,延迟应答,捎带应答

TCP还有定时器,比如超时重传定时器,保活定时器,TIME_WAIT定时器等。

6、面向字节流

TCP有发送缓冲区和接收缓冲区,应用层发给传输层的数据,是以字节为单位发送的,数据可以拆分成几个字节为一组。数据统统发给TCP后,TCP存在发送缓冲区右边部分,通过滑动窗口,一块块地发送到对端主机的接收缓冲区内。这也就是面向字节流,发送接收都已字节为单位。无论上层怎样读取发送,TCP都以字节为单位来相互拷贝。

下层如何发送接收,失败成功,上层并不关心,每层做每层的事,每层只关心这一层,这也就是流。

7、粘包问题

TCP是被上层使用套接字进行访问的,TCP使用的数据都是上层发送过来的,不过因为面向字节流,TCP并不知道这些数据,而上层知道,那么TCP如何保证读到的是完整报文?读一个完整的或者读多个完整的,但每一个都分开,这种读取完整报文就是粘包问题,也叫做粘包问题。在之前的代码实现中,可以循环读取,每次读取都做解析,分成各个成员。

计算机解决粘包问题有很多办法,比如定长包,分割符,报头加相关信息等,不过本质上这个问题的解决就是明确两个包之间的边界。UDP没有这个问题,因为UDP报文的长度都能够在报头中知道,且因为UDP报文需要处理。TCP中没有有效载荷长度,两个TCP报文之间的分离,是由应用层自主完成的,TCP报文不做处理,就是存储在缓冲区内。

8、异常情况

一个进程运行时申请了很多资源,在还没处理好资源,没有关闭像malloc,fd这样的时候,进程终止,这时候内存泄漏不存在,因为进程挂了,就由bash管理所有资源,页表,地址空间等等,也就是被回收了。网络这里也是这样,建立的连接都是OS做的,无论是否异常断开,OS都会进行挥手再断开,由OS决定。异常断开,比如拔网线,拔了之后,服务器不知道客户端断了连接,以为还有连,服务器也有保活策略,隔一段时间发去报文询问,如果没有应答服务器就断掉连接。如果刚拔又插上,可能服务器只发过一次保活信息,客户端因为断开过连接,但是它自己又不知道,接到保活信息才知道自己以前的某个连接异常,就会发送RST报文让服务端重置连接。

TCP的连接长短是由应用层做的。活跃连接是经常交互的连接,这个好管理;如果建立一个长连接,但不怎么交互,但却要一直挂着连接,不能断,这样的连接维护起来成本比较高点,如果这时候TCP插手关掉连接,那么对应用层就有不好的影响,但长时间挂着TCP又得不断询问。所以实际上,连接的维护是由应用层来做的,保活一般以小时为单位。

9、全连接、半连接

三次握手,客户端第一次发送过去SYN,服务器发送SYN + ACK应答后服务器处于SYN_RECV状态,这是半连接状态。TCP协议需要在底层维护全连接队列,队列长度就是listen接口第二个参数 + 1。假设第二个参数为1,此时只能由两个连接成功,成为全连接状态,其它再发送请求时,服务器只能处于SYN_RECV状态,这些半连接状态的连接就会被维护在半连接队列中,维护的时间很短,这个时间就是在等待上层把全连接的连接取走。全连接是指已经连接成功,但还没被应用层读取的连接。半连接队列不能太长,效率低了且不如增大-长全连接队列或者增加服务器吞吐量,会过多消耗OS本身的资源,客户端也不愿意等。

结束。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/333763.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

AI大语言模型会带来了新一波人工智能浪潮?

以ChatGPT、LLaMA、Gemini、DALLE、Midjourney、Stable Diffusion、星火大模型、文心一言、千问为代表AI大语言模型带来了新一波人工智能浪潮,可以面向科研选题、思维导图、数据清洗、统计分析、高级编程、代码调试、算法学习、论文检索、写作、翻译、润色、文献辅助…

eclipse正则表达式替换 Find/Replace

Find/Replace 对话框中使用正则表达式 CTRLF 打开 Find/Replace 对话框勾选 Regular expressions ​ 匹配注释 下图中的Find:/.*/ ​ 匹配换行符 换行符:\R 下图中的Find表达式:\R.*Excel.* ​ 新增空行 /** 替换为 \R\t/** ​ 选…

FreeRTOS学习总结(二)FreeRTOS任务创建和删除API函数

实现动态创建任务流程 任务控制块结构体成员介绍 typedef struct tskTaskControlBlock {volatile StackType_t * pxTopOfStack; /* 任务栈栈顶,必须为TCB第一个成员 */ListItem_t xStateListItem; /* 任务状态列表项 */ Li…

【深度学习每日小知识】Data Augmentation 数据增强

数据增强是通过对原始数据进行各种转换和修改来人工生成附加数据的过程,旨在增加机器学习模型中训练数据的大小和多样性。这对于计算机视觉领域尤为重要,因为图像经常被用作输入数据。 计算机视觉中的数据增强 数据增强的主要目标是解决过拟合问题&…

abp vnext 下载指定版本的项目

开发环境 Win11 vs2022 abp vnext 下载地址:Get Started | ABP.IO 下载abp框架之前,需要先安装CLI,打开命令提示符,执行以下命令即可,这个也可以指定版本下载,这里就不做介绍了,以及删除命令…

110.线程(创建、终止)

一、线程概述 ◼ 与进程(process)类似,线程(thread)是允许应用程序并发执行多个任务的一种机 制。一个进程可以包含多个线程。同一个程序中的所有线程均会独立执行相同程序,且共 享同一份全局内存区域&…

低抖动可编程SPXO SG-8200CG, SG-8201CG -高稳定性和低抖动特性

描述 SG-8200CG和SG-8201CG (sg -8201系列)利用爱普生新的低噪声分n锁相环技术&#xff0c;与上一代爱普生可编程晶体振荡器相比&#xff0c;稳定性提高了约2x&#xff0c;相位抖动降低了<1/25。sg -8201系列可编程为1.2MHz至170MHz的任何频率&#xff0c;工作温度范围可达…

C#,背包问题(Knapsack Problem)贪心算法的源代码

背包问题&#xff08;KnapSack Problem&#xff09;的相关算法是常用的规划算法。 一、什么是背包问题&#xff1f; 背包的问题是&#xff0c;你有一个“袋子”&#xff0c;可以装有限数量的物品&#xff0c;鉴于你有一组物品可以从每个物品中选择&#xff0c;每个物品都有各自…

Spring基于注解的AOP控制事务

首先在.xml中开启sprong对注解事务的支持 applicationContext.xml <tx:annotation-driven transaction-manager"transactionManager"/> 然后再Service中加上注解 service Service Transactional(readOnlytrue,propagation Propagation.SUPPORTS) public cl…

MySQL高可用解决方案演进:从主从复制到InnoDB Cluster架构

&#x1f482; 个人网站:【 海拥】【神级代码资源网站】【办公神器】&#x1f91f; 基于Web端打造的&#xff1a;&#x1f449;轻量化工具创作平台&#x1f485; 想寻找共同学习交流的小伙伴&#xff0c;请点击【全栈技术交流群】 当谈论MySQL高可用性解决方案时&#xff0c;从…

java中实现对文件高效的复制

不多说我们直接上代码&#xff1a; 这个是使用NIO包下的FileChannel和ByteBuffer进行文件的操作的&#xff0c;会比较高效。

计算机毕业设计 基于SpringBoot的公司资产网站的设计与实现 Java实战项目 附源码+文档+视频讲解

博主介绍&#xff1a;✌从事软件开发10年之余&#xff0c;专注于Java技术领域、Python人工智能及数据挖掘、小程序项目开发和Android项目开发等。CSDN、掘金、华为云、InfoQ、阿里云等平台优质作者✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精…