在 TCP 中,滑动窗口是一个非常重要的概念,因为是以它为基础来进行流控和拥塞控制。
- 流量控制,根据接收端可接受的数据大小调整发送速率
- 拥塞控制,根据网络拥堵状态调整发送速率
流量控制
发送端
发送端的结构如下:
发送端的结构由如下几部分组成:
- 已发送且已收到 ack
- 已发送但还没收到 ack
- 可发送还未发送部分,也称为可用窗口
- 不可发送部分
发送端窗口大小 = 已发送未 ACK + 可以发送部分。
假设发送方接收到 ack 14
,那么窗口会整体右移 1,并同时发送 18。可用窗口变为 19 ~ 22
。如下图所示:
接收端
接收端的结构如下:
它包括三部分:
- 接收已确认部分。
- 等待被接收的数据,也就是接收窗口。若到来的数据包不是所期望的,则先缓存着。
- 不可接收部分
接收方窗口大小根据缓冲区大小、被应用层读取的数据、期待收到的数据大小动态变化。
// 缓冲区大小 - 待读数据大小
rwnd = maxRecvBuffer - (nextExpected - lastRead - 1)
当接收到期望的数据时,接收窗口可整体右滑。但是如果应用程序读取数据较慢,那么接收窗口会慢慢变小。
比如上图中缓冲区大小为 8,下一期望收到的字节为 19,被程序读取的最后一字节为 14,那么接收窗口 = 8 - (19 - 14 - 1) = 4
。
-
假设接收端收到了期望的数据 19,且 15 被读取,那么窗口变为如下:
接收窗口整体右移,大小保持不变。
-
假设接收端收到了期望的数据 19,但 15 未被应用程序读取,那么窗口变为如下:
接收窗口左边界右移,但右边界不变,因此窗口会变小,大小变为 3。
拥塞控制
拥塞控制主要是根据当前网络状态来调整拥塞窗口 cwnd,并结合接收窗口 rwnd,取其最小值,即 wnd = min(cwnd, rwnd)
,来调整发送端的速率,主要包括如下几个算法:
- 慢启动,slow start。
- 达到慢启动阈值 ssthresh,进入拥塞避免阶段,congestion avoidance。
- 超时重传,Retransmission Time Out。
- 快速恢复,Fast Recovery。
其中发送端需要满足如下条件,即已发送尚未确认包
的长度小于窗口大小,也就是可用窗口 > 0。
lastSendByte - lastAckedByte <= wnd
慢启动
为了避免在一开始发送数据时就将带宽占满,采用了慢启动的方式指数级增长 cwnd 大小。
假设初始 cwnd = 1 mss,在收到一个 ack,cwnd += 1,变为 2;
此时,可发送 2 mss,再次收到 2 个 ack 后,cwnd += 2,变为 4;
此时,可发送 4 mss,再次收到 4 个 ack 后,cwnd += 4,变为 8;
...
如此,每次都翻倍增长。
拥塞避免
但是指数级的增长会以非常快的速度达到一个值,有可能会超过网络带宽,这样单方面增加窗口大小就无意义。因此在达到慢启动阈值后 ssthresh,会进入拥塞避免阶段。
在收到 1 个 ack 后,窗口大小增加 1/cwnd。在经过 1 RTT 后,窗口大小 + 1。以线性方式缓慢增长。
cwnd += 1/cwnd
为什么经过 1 RTT 后,cwnd 会加 1 呢?因为 tcp 会一次性发送 cwnd 个数据,在收到这些数据的所有 ack 时,经过了 1 RTT 的时间。
超时重传
当发送端处于超时重传的情况下时,说明网络拥塞有点严重,因此它采用比较激进的方式,将 cwnd 直接降为 1,ssthresh 减半,再进行慢启动的过程。
ssthresh = cwnd /2
cwnd = 1
快速恢复
由于超时重传的处理会导致发送速率断崖式的下降,而在收到 3 个重复的 ack 时,说明网络环境还不是太差,也不必采用太激进的措施。此时发送端会进入快速重传的阶段,对于 cwnd 的处理会采取快速恢复的方式。
当收到 3 个重复的 ack 时,发送端将阈值和窗口更新如下。然后会重传重复的 ack 对应的数据包。
cwnd /= 2
ssthresh = cwnd
在上面数据的基础上,快速恢复算法如下:
-
首先,
cwnd += 3
,表示收到了 3 个重复 ack。 -
重传重复 ack 对应的数据包。
-
再次收到重复的 ack,
cwnd += 1
。 -
收到新的 ack,
cwnd = ssthresh
,进入拥塞避免。
可结合如下图理解:
流程如下:
- 当第一次重复收到 ack6 时,发送端进入快速重传阶段,此时窗口不变;
- 当第三次重复收到 ack6 时,更新窗口大小,并重传数据包。
- 接下来会有 2 次收到重复的 ack6,
cwnd += 1
。 - 最后收到新的 ack12,cwnd 更新为 ssthresh,进入拥塞避免。
网友评论