TCP流量控制与拥塞控制

1.滑动窗口

TCP使用滑动窗口机制来控制数据发送速度。滑动窗口机制的实现方式是发送方发出的数据,仍然保留在发送缓存中,收到接收方的确认应答后才从发送缓存中丢弃。

1.1 发送窗口

滑动窗口的大小由发送方的发送窗口swnd确定,表示发送方不必等待接收方确认可以连续发送的数据量。

发送方的发送窗口swnd取接收方的接收窗口rwnd和发送方的拥塞窗口cwnd两者中的较小值,即swnd = min(rwnd, cwnd)。接收窗口rwnd和拥塞窗口cwnd是不断变化,动态调整的,所以发送窗口swnd也是不断变化的。

接收窗口rwnd是接收方在确认数据时向发送方通告的值,表示接收方当前可用的接收缓存大小。TCP使用接收窗口rwnd实现流量控制,避免发送方发送的数据量超出接收方的处理能力。

拥塞窗口cwnd是发送方自己估算出的值,表示当前网络状况允许的合适数据发送速度。TCP使用拥塞窗口cwnd实现拥塞控制,避免发送方发送的数据量超过网络的处理能力。

1.2 最大报文段

最大报文段MSS = MTU -- TCP头部 -- IP头部 = 1500 -- 20 -- 20 = 1460。

TCP 连接建立时,通信双方建立连接时在SYN报文的选项字段中交换各自支持的MSS 值,最终取双方都支持的较小值作为实际使用的 MSS。

通信双方协商MSS的好处:

(1)可以避免 IP 分片,TCP 通过MSS控制数据段大小,确保数据在传输前就被分割成合适的块,避免 IP 层分片重组带来的性能损耗。

(2)可以优化传输效率。太小的MSS会增加协议头比例,降低有效数据传输效率。太大的 MSS可能导致数据包在某些网络设备上被丢弃。

(3)在带宽充足的网络中,适当增大MSS可显著提升传输性能,提高吞吐量。

2. 流量控制

发送方根据接收方确认的接收窗口rwnd获知接收方的数据处理能力,实现流量控制。

2.1 接收窗口rwnd

TCP头部包含窗口大小字段。接收方收到数据后,会在确认数据的应答ACK报文中通告自己的接收窗口rwnd,告知发送方自己当前可用的缓存大小,作为发送方控制数据发送速度的一个参考因素。

2.2 窗口扩大因子

TCP头部接收窗口大小只有16位,最大值是64k,真实的接收缓存可能要大得多,收发双方可以使用窗口扩大因子选项来协商实际窗口的放大倍数。

窗口扩大因子必须在建立TCP连接时协商设置,连接建立之后不可更改,连接双方使用SYN和SYN-ACK报文携带TCP头部窗口扩大因子选项,互相告知对方自己的接收窗口大小。

实际接收窗口大小 = TCP头部接收窗口大小 * 窗口扩大因子

2.3 窗口收缩

当服务端系统资源非常紧张的时候,操作系统可能会直接减少接收缓冲区大小,若应用程序无法及时读取缓存数据,就会出现数据丢失。为了避免数据丢失,TCP规定不允许同时减少接收缓存又收缩窗口,而是采用先收缩窗口,过段时间再减少缓存。

2.4 窗口关闭

如果没有可用缓存,接收方会在ACK报文中把接收窗口大小设置为0,阻止发送方继续发送数据,这就是窗口关闭。

当发生窗口关闭时,接收方处理完数据后,会在ACK报文中把接收窗口大小设置为非0,通知发送方可以恢复数据发送。

如果通告窗口变化的ACK 报文在网络中丢失了,发送方就无法继续发送数据。为了解决这个问题,TCP 为每个连接设有一个持续定时器,只要TCP连接一方收到对方的窗口关闭通知,就启动持续计时器。

如果持续计时器超时,发送方会发送窗口探测报文,接收方在应答这个探测报文时,给出自己现在的接收窗口大小。

窗口探测的次数一般为3,每次大约30-60 秒,不同的实现可能会不一样。如果3次过后接收窗口还是0的话,有的TCP实现就会发RST报文来重置连接。

2.5 糊涂窗口综合症

如果接收方来不及取走接收缓存里的数据,就会导致发送方的发送窗口越来越小。如果接收方应用层从接收缓存中读取几个字节后,协议栈立即通知发送方现在有几个字节的窗口,发送方立即发送几个字节的数据,就会出现糊涂窗口综合症。

出现糊涂窗口综合症的原因是:接收方通告一个小窗口,发送方发送小数据包。

要解决糊涂窗口综合症,就要让接收方不通告小窗口,让发送方避免发送小数据包。

2.5.1 接收方不通告小窗口

当窗口小于min(MSS, 接收缓存/2 ) ,也就是小于MSS与接收缓存一半中的最小值时,就会向发送方通告窗口为0,阻止发送方继续发数据。等接收方从缓存中读取一些数据后,窗口大小 >= MSS,或者接收方接收缓存有一半可以使用,就可以开启窗口让发送方继续发送数据。

2.5.2 发送方不发送小数据包

发送方可以使用Nagle算法来控制尽量不发送小数据包。

启用Nagle算法,只有满足两个条件中的任意一个后,协议栈才继续发送数据:

(1)数据量大小 >= MSS,且窗口大小 >= MSS;

(2)收到接收方对上个小数据包的ACK,即最多只允许有一个未被确认的小数据包(数据量< MSS)。

Nagle算法默认是打开的,实时交互式应用需要关闭Nagle算法,如telnet或ssh等。可以通过为套接字设置TCP_NODELAY选项来关闭Nagle算法。

3.拥塞控制

发送方根据网络状况动态估算可以发送的数据量,实现拥塞控制。

发送方根据拥塞窗口cwnd和慢启动阈值ssthresh(slow start threshold)之间的数值关系来选择不同的拥塞控制算法。

cwnd < ssthresh时,使用慢启动算法。

cwnd == ssthresh时,既可以使用慢启动算法,也可以使用拥塞避免算法。

cwnd > ssthresh时,使用拥塞避免算法。

拥塞控制算法的切换过程入下图所示:

3.1 慢启动

TCP连接刚建立时,使用慢启动算法,先少发点数据试探,每经历一轮RTT,发送数据量就指数性快速增长,直到达到慢启动阈值ssthresh。

TCP连接刚建立时,拥塞窗口cwnd的默认初始值一般是几个MSS,假设为1个MSS,慢启动阈值ssthresh的默认初始值一般是65536字节。

慢启动算法的进入条件是:cwnd < ssthresh。

慢启动算法只改变cwnd的值,不改变ssthresh的值。

慢启动算法改变cwnd的规则是:发送方每收到一个ACK,cwnd增加1个MSS。

若当前cwnd=N * MSS,一轮RTT会连续发出N个MSS数据包(假设cwnd < rwnd,发送方不必等接收方应答ACK即可连续发送的数据量是cwnd),相应地也会连续收到接收方应答的N个ACK,接收方收到N个数据包后只合并应答1个ACK的情况按应答N个ACK算。也即一轮RTT后cwnd = cwnd + N * MSS = N * MSS + N * MSS = 2* N * MSS = 2cwnd。相当于每经历一轮RTT,cwnd增加1倍,所以慢启动算法的数据发送速度是指数性快速增长的。

3.2 拥塞避免

当发送数据量达到慢启动阈值ssthresh后,发送方会启用拥塞避免算法,发送数据量不再指数性快速增长,而是线性缓慢增长,这样可以防止短时间内发送大量数据造成网络拥塞。

拥塞避免算法的进入条件是:cwnd > ssthresh。

拥塞避免算法只改变cwnd的值,不改变ssthresh的值。

拥塞避免算法改变cwnd的规则是:发送方每收到一个ACK ,cwnd增加(1/cwnd)* MSS。

若当前cwnd=N * MSS,一轮RTT会连续发出N个MSS数据包(假设cwnd < rwnd,发送方不必等接收方应答ACK即可连续发送的数据量是cwnd),相应地也会连续收到接收方应答的N个ACK,接收方收到N个数据包后只合并应答1个ACK的情况按应答N个ACK算。也即一轮RTT后cwnd = cwnd + N * (1/cwnd) * MSS = N * MSS + N * (1/N) * MSS = (N+1) * MSS。相当于每经历一轮RTT,cwnd增加1个MSS,所以拥塞避免算法的数据发送速度是线性缓慢增长的。

3.3 拥塞发生

发送方发出的数据丢失,或者接收方应答的ACK报文丢失,导致发送方没有及时收到接收方的应答ACK,会让发送方认定数据传输超时,启动超时重传。

发生超时重传后,发送方会使用拥塞发生算法改变ssthresh和cwnd的值,具体改变为:

(1)ssthresh设为当前cwnd的一半,即ssthresh = cwnd/2。

(2)cwnd重置为初始值,假设为1个MSS。

使用拥塞发生算法后,ssthresh和cwnd迅速减小,数据发送速度会迅速下降。

使用拥塞发生算法改变ssthresh和cwnd,会导致cwnd 小于 ssthresh,此后,发送方会重新使用慢启动算法控制数据发送速度,如下图所示。

3.4 快速恢复

3.4.1 快速重传

发送方连续发出多包数据,若前边部分数据丢失,后续每次发送的数据到达接收方后,接收方应答的ACK报文TCP头部填入的期望序列号都是前边丢失部分数据的起始序列号。

发送方连续收到3个期望序列号相同的ACK后,可以获知前边部分数据丢失,会立即重传丢失的部分数据,不必等待超时,这就是快速重传。

快速重传能够避免等待 RTO 超时带来的延迟,大大缩短了丢包后的恢复时间,适用于丢包率较高但延迟较低的网络环境。

3.4.2 快速恢复

因为发送方既然能收到3个重传的ACK,说明发送方发送的数据大部分到达了接收方,丢包率不高,也说明网络拥塞并不严重,不需要把数据发送速度降得过低。

发生快速重传后,发送方会使用快速恢复算法改变cwnd和ssthresh的值,具体改变为:

(1)ssthresh设为当前cwnd的一半,即ssthresh = cwnd/2。

(2)cwnd = ssthresh + 3*MSS。

发送方收到3个重复的ACK,所以cwnd在ssthresh的基础上加3个MSS。

使用快速恢复算法改变ssthresh和cwnd后,会导致cwnd大于ssthresh。

若快速重传的数据及时收到接收方的应答ACK,则发送方会使用拥塞避免算法控制数据发送速度。

若快速重传的数据超时仍未收到接收方的应答ACK,则会产生超时重传,发送方会使用慢启动算法控制数据发送速度。

相关推荐
虹科网络安全7 小时前
使用艾体宝 IOTA 10 CORE+ 监控企业网络中的 AI 流量
网络·人工智能
醉颜凉8 小时前
网络安全必学:粘性MAC地址(Sticky MAC)原理与应用全解析
运维·服务器·网络·安全·web安全
晊晌_h8 小时前
嵌入式从0到精通——Linux C|TCP 并发服务器实现方案详解
服务器·开发语言·tcp/ip
广州灵眸科技有限公司9 小时前
从手动三步到上电即连:4G模组systemd开机自连方案
linux·运维·服务器·开发语言·网络·人工智能·php
埃科光电9 小时前
16K万兆网口彩色线阵相机:四倍带宽 高速真彩检测新方案
网络·图像处理·数码相机·计算机视觉·制造·相机
运维全栈笔记10 小时前
Windows 安装 WSL2 并运行 Ubuntu 24.04 指南
linux·网络·windows·ubuntu
qq_4523962311 小时前
第十篇:《eBPF 可观测性:零侵扰的深度内核追踪》
服务器·网络·php
迪康Defender11 小时前
政企内网终端安全建设:资产‑管控‑防护‑审计闭环能力拆解
运维·网络·安全·web安全·终端安全管理
晓天衡宇•评测社区11 小时前
Seedance 2.5 登顶图生视频榜单,Wan 3.0 在游戏与教育场景进入前列
前端·javascript·网络
charliejohn12 小时前
计算机考研 408 网络 以太网、ARP、NAT、DHCP概念
网络·计算机网络