前言

看完了《TCP/IP详解 卷一》,对TCP/IP协议簇的认知多了一些。总结一下TCP窗口有关的慢启动、拥塞避免、快速重传、快速恢复的概念。

TCP滑动窗口

窗口有两种,通告窗口(Receiver Window,rwnd)和拥塞窗口(Congestion Window,cwnd)。

  • 通告窗口:通告窗口表明了接收端当前的接受能力。TCP在发送端和接收端都是有缓冲区的,通告窗口声明了当前接收端的缓冲区还能接收的字节大小。这个数值会在TCP报文里携带。
  • 拥塞窗口:拥塞窗口不被TCP报文传输,是发送端基于拥塞避免算法算出来的一个窗口。这个窗口限制了发送方的发送速率避免网络拥塞。

两个窗口共同组成了一个滑动窗口。简单来说,通告窗口是强制限制,拥塞窗口是自发限制。

有一点要注意的是,窗口的单位用字节表示,但是拥塞窗口的调整总是以一个MSS的倍数来调整。

这里用书上的图描述滑动窗口, upload successful 当一个TCP发送方发送数据的时候就会查看可用窗口能否发送(如果启用了Nagle算法,可用窗口必须大于等于一个MSS,发送方才发送数据)

upload successful 上面是抓包得到的一个报文,Win=2027是一个通告窗口,表示服务器的缓冲区还能接受2027字节的数据。

拥塞控制

upload successful 上图是一个tcp刚开始传输数据时的速率变化走向。

拥塞避免、慢启动、快速重传、快速恢复这四个词其实并不能单独分开讲。当一个连接的网络情况不好的时候,就会丢包超时,这时就要降低发送方的发送速率防止恶化,这种就是拥塞控制。

这种机制涉及到cwnd和ssthresh两个指标,ssthresh是一个区分慢启动和拥塞避免的阈值,当拥塞发生时,分两种情况
超时:ssthresh = cwnd / 2(最小为2MSS),cwnd = 1MSS,进入慢启动
丢包:ssthresh = cwnd / 2(最小为2MSS),cwnd = ssthresh + 3MSS,进入快速重传

慢启动

慢启动其实是发送速率重新计算,cwnd 初始值为一个数据报大小,ssthresh初始值为65535,是一个然后在到达阈值之前,每接收到一个新的ACK,cwnd就会增加一个报文段的大小,这样子慢启动其实是以指数增加速率.

拥塞控制

upload successful 上图是一个tcp刚开始传输数据时的速率变化走向。

拥塞避免、慢启动、快速重传、快速恢复这四个词其实并不能单独分开讲。当一个连接的网络情况不好的时候,就会丢包超时,这时就要降低发送方的发送速率防止恶化,这种就是拥塞控制。

这种机制涉及到cwnd和ssthresh两个指标,ssthresh是一个区分慢启动和拥塞避免的阈值,当拥塞发生时,分两种情况
超时:ssthresh = cwnd / 2(最小为2MSS),cwnd = 1MSS,进入慢启动
丢包:进入快速重传

慢启动

慢启动其实是发送速率重新计算,cwnd 初始值为一个数据报大小,ssthresh初始值为65535,是一个然后在到达阈值之前,每接收到一个新的ACK,cwnd就会增加一个报文段的大小,这样子慢启动其实是以指数增加网速到一个比较平衡的水平。

拥塞避免

当cwnd大于等于ssthresh时进入拥塞避免状态,在一个RTT内无论收到多少ACK都只将cwnd增加一个报文大小,从时间上来看网速线性增加。

快速重传和快速恢复

快速重传指,当收到重复的3个ACK报文时(duplicate ack),设置ssthresh = cwnd / 2(最小为2MSS),cwnd = ssthresh + 3MSS,然后进入快速恢复阶段。

暂停发送新的报文,重传丢失报文。

接下来每收到重复的ACK时,将cwnd增加一个报文大小。如果cwnd大于未确认报文大小(报文丢失后我们还在发新的报文,未确认报文指丢失报文到最后一个报文之间报文总大小),可以发送新报文。

接下来如果收到新的ACK报文,将cwnd设置为ssthresh,也就是网速降为一半,并进入拥塞避免阶段。

总的来说,网速一直处于一个动态调整的过程,一个连接上cwnd随时间的变化如图所示

upload successful

还有一点,上面关于cwnd的比较其实还要考虑rwnd的值,如果rwnd>cwnd,应取rwnd去比较,毕竟两者决定了可用窗口大小。

后记

TCP拥塞控制其实还有很多改进未去了解。比如当收到重复的3个ACK报文时,其实不一定只丢了一个报文,所以网速可能指数下降,不能达到快速恢复的目的。