基本行为

(1) 发包的时机
每个ACK都有可能触发发包,是否发包取决于根据’(2)’中的公式所算结果是否大于零。

  • RTT测量的ACK会启动发包。(这一条是错的)
  • 重复ACK会启动发包。
  • 紧跟在重复ACK后回复的第一个新的ACK会启动发包。
  • 快速重传、超时重传也会启动发包。
    (2)发包的数量:
    发送端根据启动发包时刻的发送窗口、接收窗口、拥塞窗口大小来确定发包数量。计算公式如下:
    发包数量 = min(发送窗口大小, 接收窗口大小, 拥塞窗口大小) - 已发送未确认数据的字节数

RTT测量原理

基本原理:在一个RTT时间内只会启动一次测量。用于RTT测量的ACK才会启动发包,期间收到的其它ACK不启动发包(重复ACK以及跟随其后的第一个新的ACK除外~)

RTT_Measurement

(数据包交换以及RTT测量,图来源于网络我不想画图了。。。大概就这样)

滑动窗口原理

参见 《TCP性能分析技术:Windows下TCP/IP协议栈的实现中》的协议栈图

在接收窗口受限的情况下,发包数量取决于接收窗口的大小:接收窗口增大,则发包数量增加;接收窗口减小,则发包数量减少。

拥塞窗口更新

发送端对接收到的每个ACK都会启动拥塞窗口更新。具体如何更新和接收到ACK时所处的阶段是有关的。

(1)慢阶段启动
TCP建立的时候,CWND = 1(MSS),之后每收到一个ACK,CWND = CWND + 1,直到满足 CWND ≤ ssthresh(慢启动阈值),则慢启动阶段结束。之所以叫“慢启动”,是相对于没有拥塞控制只有流控制的情况下发送端一次发下不超过接收窗口大小的数据来讲的。

启动过程:
[慢启动门限更新] :初始化为65535 Bytes,发生拥塞时调整为当前拥塞窗口的一半。
[拥塞窗口更新]:CWND = CWND + 1,假设接收端收到了1个包,回1个ACK,ssthresh = 16

CWND = 1,第一个RTT期间,发出1个包,回来1个ACK
CWND = 2,第二个RTT期间,发出2个包,回来2个ACK
CWND = 4,第三个RTT期间,发出4个包,回来4个ACK
CWND = 8,第四个RTT期间,发出8个包,回来8个ACK
CWND = 16,达到慢启动门限,慢启动阶段结束。

这里为了方便,在描述拥塞窗口的时候用的单位都是1个MSS(最大报文段长度,Maximum Segment Size),实际上使用的拥塞窗口单位都是Bytes(字节)。

慢启动特征:
拥塞窗口大小是随着时间指数上升的。
slow_start_stage
(慢启动和拥塞避免情况下拥塞窗口大小随时间的变化规律,图来源于网络我不想画图了。。。大概就这样)

(2)拥塞避免阶段
CWND超过慢启动门限就会进入拥塞避免阶段。

拥塞避免过程:
[拥塞窗口更新] :CWND = CWND + 1 / CWND,
假设CWND = 16,
CWND = 16, 第一个RTT期间,发出16个包,回来16个ACK,
CWND = 17, 第二个RTT期间,发出17个包,回来17个ACK,
CWND = 18, 第三个RTT期间,发出18个包,回来18个ACK,
CWND = 19, 第四个RTT期间,发出19个包,回来19个ACK,
CWND = 20, ——————

拥塞窗口的大小会随着时间线性上升。

(3)快速重传阶段
收到3个重复ACK就会启动快速重传而进入快速重传阶段。
重传数据包,不需要等待重传定时器超时。收到3个重复ACK后立即重传数据包。

(4)快速恢复阶段
快速重传结束后,不进入慢启动阶段,而是进入拥塞避免阶段,这就是快速恢复。

快速恢复过程:
[慢启动门限更新] :更新为当前CWND 的一半,即 ssthresh = CWND / 2
[拥塞窗口更新] : CWND = ssthresh + 3(MSS)

(5)超时重传阶段
在超时定时器超时之前,没有收到ACK,也没有收到重复ACK,就会进入超时重传阶段。
重传定时器超时后,重发数据包。

CWND = 1,
ssthresh = 65535

进入慢启动阶段。


上面5个阶段划分都是站在发送端的角度去考虑的。这章比较长而且不容易理解,可以消化一段时间了。