滑动窗口、流量控制和拥塞控制
1. 确认应答机制
确认应答机制是计算机网络中,用于确保数据可靠传输的一种方法。
它通过发送 ACK 数据段来通知对方,每一个 ACK 数据段都有一个确认序号,表明:
确认序号之前的所有数据都已被接收,接下来从确认序号开始发送数据。
如果对每一个发送的数据段,都要给一个 ACK 确认应答,收到 ACK 后再继续发送新的数据,就会带来一个缺点:
性能差,尤其是 RTT (数据往返时间)很大的时候。
2. 滑动窗口
既然发送一条数据,接收一个 ACK 后,再发新数据的方式效率太低。那么,一次性发送多条数据,就可以大大提升性能。
-
拥塞窗口(cwnd):
发送方
在没有收到 ACK 的情况下,最大可发送数据量。 -
接收窗口(rwnd):
接收方
接收缓冲区,剩余空间的大小。 -
滑动窗口大小 = min(拥塞窗口大小, 接收窗口大小)
上图中,主机1
一次性发送 3 个数据段,收到第 1 个 ACK 后窗口向右移动,发送第 4 个数据段。
- 滑动窗口左边的数据:已经被发送,且已经收到来自接收方的 ACK 数据段。
- 滑动窗口右边的数据:尚未被发送到接收方的数据。
- 滑动窗口中的数据:已经被发送,但还未收到来自接收方的 ACK,处于
待确认
状态。
如果这部分数据在网络传输中丢失或损坏,发送方可以根据超时机制或其他方式检测到,并重新发送这部分数据;
当发送方接收到对滑动窗口中的数据确认后,窗口右移,被确认的数据被移除窗口,新的、未被发送的数据进入窗口。
3. 丢包重传
3.1 数据段顺利到达,但 ACK 丢失
确认序号:确认序号(Ack = x)之前的所有数据,都已经被收到。
这种情况下,部分的 ACK 包丢失无影响,可以通过后面的 ACK 包确认数据已顺利到达。
3.2 数据段丢失
主机1 发送的 data (Seq = x+2)
丢失,主机2 无法对这一数据段做确认应答,因此 ACK 包的确认序号始终为 x+2
;
主机1 连续收到三个相同确认序号的应答后,就会触发 快重传
机制,对 data (Seq = x+2)
进行重新发送;
主机2 收到 data (Seq = x+2)
后,发送应答的确认序号为 x + 4
,因为 data (Seq = x+3)
和 data (Seq = x+4)
之前已经被收到,并被放入了系统内核的接收缓冲区中。
4. 流量控制
流量控制是一种机制,根据接收方接收数据的能力,管理发送方发送数据的速率。
接收方将接收缓冲区的剩余容量,放入 TCP 头部的 16位窗口大小
中,通过 ACK 数据段通知发送方;
发送方会根据窗口大小的值,调整发送数据的速度。
-
接收缓冲区的剩余空间变小,发送速率减慢。
-
接收缓冲区的剩余空间变大,发送速率加快。
-
接收缓冲区满了,会将窗口大小设置为 0,此时发送方不再发送数据;
发送方定期发送一个窗口探测数据段(只包含报头),得到接收方接收缓冲区剩余空间大小。
5. 拥塞控制
TCP 拥塞控制的主要目的是,防止过多的数据被注入网络,导致网络拥塞,从而保证数据段高效、可靠的传输。
拥塞控制的两个主要阶段:
- 慢启动阶段
- 拥塞避免阶段
5.1 慢启动阶段
慢启动的目的:在连接初始阶段,避免一次性发送过多数据,导致网络突然拥塞。
cwnd
(拥塞窗口) 被初始化为 1 MSS(最大报文段长度);
ssthresh
(慢启动阈值)被初始化某一个预设值(如接收方窗口大小)。
在慢启动阶段,发送方每接收到一个 ACK,cwnd 就增加 1 MSS。这种方式导致 cwnd 呈指数增长,因为 cwnd 在每一个数据往返时间(RTT)内翻倍。
通过指数增长,TCP 可以迅速发现和利用网络的可用带宽。
当 cwnd 达到慢启动阈值(ssthresh),进入拥塞避免阶段。
5.2 拥塞避免阶段
拥塞避免的目的:避免慢启动之后,继续指数增长导致网络拥塞。
cwnd 以线性的方式增长,每经过一个 RTT,增加 1 MSS。
当检测到网络拥塞时,进入快恢复阶段:
- ssthresh = cwnd / 2; // 设置新的慢启动阈值
- cwnd = 1;