TCP的拥塞控制 (二)

时间:2024-09-21 09:06:02

TCP Reno

TCP  Reno引入了ssthresh(Slow Start threshold)变量,作为TCP的Slow Start和Congestion Avoidance两个阶段的分界线。

当cwnd < ssthresh时,TCP保持在Slow Start阶段;

当cwnd >= ssthresh时,TCP进入Congestion Avoidance阶段。

ssthresh实际上影响着TCP的性能,但其初始值在RFC中没有明确定义,可以为任意大的值,在实现时一般初始化为rwnd。

TCP Reno拥塞控制算法继承了“数据包守恒准则”,保证处于网络中的packet的总量是守恒的。它通过4个算法保证这一点:

1. Slow Start

在TCP连接建立之后,由于不知道实际可用的网络带宽,因此采用Slow Start算法,小心翼翼地对网络情况进行探测。

进入Slow Start阶段,首先设置cwnd=1,接着cwnd会随着时间的推进呈指数级增加(因此,其过程并不slow)。具体做法是每收到一个ACK,就对cwnd+1,这样相当于每经过一个RTT,cwnd就翻一番。

在遇到两种情况时,Slow Start阶段会截止:

(1)当cwnd达到ssthresh时,此时TCP会进入Congestion Avoidance阶段。

(2)当拥塞发生时,此时又分两种情况:

(2.1)如果是超时,会重传未被响应的packet,并将ssthresh设置为cwnd/2,并将cwnd重置为1,然后重新进入Slow Start阶段。

(2.2)如果是3个重复ACK,会先进行Fast Retransmit,然后进入Fast Recovery阶段。

2. Congestion Avoidance

在该阶段,cwnd不再像Slow Start那样指数级增长,而是线性增长。具体做法是每收到一个ACK,就对cwnd+1/cwnd,这样相当于每过一个RTT,cwnd都加1。

当拥塞发生时,Congestion Avoidance阶段即截止,接下来的过程与Slow Start处理拥塞的方式相同:

(1)如果是超时,会重传未被响应的packet,并将ssthresh设置为cwnd/2,并将cwnd重置为1,然后进入Slow Start阶段。

(2)如果是3个重复ACK,会先进行Fast Retransmit,最后进入Fast Recovery阶段。

3. Fast Retransmit

当检测是否丢包时,每次都要等待超时的发生,会浪费很长时间,因此引入了Fast Retransmit机制。

通过TCP的机制可知,sender只要收到3个重复ACK,即认为丢包发生,此时会立即重传丢失的包,而不再等待超时的出现。

4. Fast Recovery

为了解决丢包后进入Slow Start引起的效率降低,在Fast Retransmit的基础上,又引入了Fast Recovery机制。

该阶段首先将ssthresh设置为cwnd/2,然后重传丢失的包,再对cwnd进行充气(而不是SlowStart那样将cwnd重置为1),具体做法是在cwnd=ssthresh+3(用以反映3个packet正常离开了network)。

之后,每当再次收到一个重复ACK时,sender都会对cwnd+1,这是为了反映一个packet正常离开了network。

这里可能有两个疑问:

(1)怎么得知一个packet正常离开了network呢?这是因为receiver只有在收到packet之后,才会回复ACK,既然sender收到了ACK,说明有一个packet被receiver接收,即正常离开了network。

(2)那么,为什么需要对cwnd+1呢?这是因为一个packet离开了network,使得network不再饱和,为了使network重新平衡,需要发送新的packet到network中,这就必须通过增大cwnd来实现。

随着cwnd的增大,会将新进入窗口的packet发送出去。这个过程称为inflating。

直到收到新的ACK之后,inflating截止,进入deflating过程。所谓deflating,即将cwnd设置为ssthresh。

为什么收到新的ACK后,需要进行deflating呢?这是因为,新的ACK意味着,刚进入Fast Recovery时重传的packet已经被接收,该ACK即是receiver对重传packet的回应。可以认为lost packet已经恢复了,可以结束Fast Recovery阶段。

值得注意的是,该ACK可能一次性响应了多个连续的packet。这是因为,从lost packet发生时起,到lost packet恢复为止,期间sender发送了多个后续packet,因此在receiver回复ACK时,会指明已接收到的最末端的packet的sequence number。