TCP重传定时器

最近在看Linux 3.0下TCP/IP的源码实现 ,发现与linux 2.6上实现许多细节变化较多,但基本机制或者说思路没有变化,变化的一些具体的算法上,更能适应今天的的高速网络,比如新的算法可以更灵活的更好的适应今天较小的网络时延。

TCP/IP协议栈共有七种定时器:连接建立定时器、重传定时器、延迟ACK定时器、持续定时器、保活定时器、FIN_WAIT_2定时器、TIME_WAIT定时器,最近主要看了一下重传定时器的实现。

作用:TCP 必须维护一个重传定时器,以进行超时重传。

问题:如何设置超时时间间隔 RTO?
时间间隔太短则可能导致大量不必要的重传,太长则导致性能下降;

超时时间间隔 RTO是跟往返时间RTT紧密相关的,通过得出跟往返时间RTT,就能够计算出超时时间间隔 RTO。TCP 采用了一个高度动态的算法,来不断的调整时间间隔,这个算法就是 Jacobson 1988 算法:

1、往返时间的测量
(1)公式及Karn算法
当一个超时和重传发生时,在重传数据的确认最后到达之前,不能更新RTT估计器。由于数据被重传,RTO已经得到一个指数退避,我们在下一次传输时使用这个退避后的RTO。
RTO = R*β(这里β是一个推荐值为2的时延离散因子)
对一个没有被重传的报文段而言,除非收到了一个确认,否则不要计算新的RTO,计算新的RTO利用如下方法
Err = M – A
A <- A + gErr
D <- D + h(|Err| – D)
RTO = A + 4D
这里M表示所测量到的RTT(接收方接收到的时间-发送方发送的时间)。A是被平滑的RTT(均值的估计器)而D则是被平滑的均值偏差。Err是刚得到的测量结果与当前的RTT估计器之差。A和D均被用于计算下一个重传时间(RTO)。增量g起平均作用,取为1/8,偏差的增益石h,取值为0.25。
(2)计算实例
(1)初始化
变量A和D分别被初始化为0和3秒。初始的重传超时使用下面的公式进行计算
RTO = A + 2D = 0 + 2 * 3 = 6s
因子2D只在这个初始化计算中使用。正如前面提到的,以后使用4D和A相加来计算RTO,这就是传输SYN所使用的RTO。
(2)结果初始SYN丢失了,然后超时引起了重传
在这种情况下,不能更新RTT估计器。应用于RTO的指数退避取为RTO = A + 4D = 0 + 4*3 = 12s,由于这是第一次超时,我们使用倍数2,因此下一个超时时间取值为24秒。再下一个超时时间倍数被4,得出48秒。
(3)直到收到重传报文的ACK,RTO停止更新
(4)当发送此后第一个数据报时,RTO没有改变,当前的RTO一直使用,直到该报文的ACK到达时,进行一个RTT测量。(假设经历了3个时钟滴答)则由于每个时钟滴答为500ms,所以M为1.5秒。
A = M + 0.5 = 1.5 + 0.5 = 2
D = A / 2 = 1
计算的RTO值为
RTO = A + 4D = 2 + 4*1 = 6
(5)当第二个数据报文段的ACK到达时,经历了1个时钟滴答(第二次更新)
Err = M(本次测量值) – A(上次计算值) = 0.5 – 2 = -1.5
A = A + gErr = 2 – 0.125 * 1.5 = 1.8125
D = D(上次计算值) + h(|Err| – D(上次计算值)) = 1 + 0.25 * (1.5 – 1) = 1.125
RTO = A(本次计算值) + 4D(本次计算值) = 1.8125 + 4* 1.125 = 6.3125

 

这个算法简单高效,但是Jacobson 算法只用于处理正常的情况,但是当发生重传后,如果收到一个确认,这时候就不用这个算法来调整 RTO 值了。因为你无法判断这个确认是针对第一次传输,还是后来的重传。在这种情况下,采用 Karn 算法来调整 RTO 的值 。

Karn 算法很简单:
1)、 对于发生重传的数据段,在收到确认后,不更新 RTT
2)、在重传的时候,RTO 是倍增的,直到达到最大值的限制。如果重传超过一定的次数,TCP 连接会断开
3)、在重传并收到确认后,如果下一次的数据段没有发生重传(即一次性收到确认),则又恢复为 Jacobson 算法。

发表评论