我们都知道,TCP发送方在规定时间内没有收到确认就要重传已发送的报文段(里面有一个超时计数器),这个逻辑很简单,但是这个超时计数器的值每次都是不一样的,也就是说:重传时间的选择是不一样的,它是如何确定的呢???
TCP下层是互联网环境,发送的报文段可能只经过一个高速率的局域网,也可能经过多个低速率的网络,并且每个IP数据报所选择的路由还可能不同。如果把超时重传时间设置太短,就会引起很多报文段的不必要的重传,使网络负荷增大。但若把超时重传时间设置的太长,那么网络空闲时间会增大,极大的降低了网络的效率
到底应该设置为多大呢????
TCP采用了一种自适应算法,它记录一个报文段发出的时间,以及收到相应的确认的时间。这两个时间之差就是报文段的往返时间RTT。TCP保留了RTT的一个加权平均往返时间RTTs(这又成为平滑的往返时间,S表示Smoothed。因为进行的是加权平均,因此获得的结果更加平滑,也就是让我们计算出的结果更加合理)。每回的第一次测量到RTT样本时,RTTs值就取为所测量到的RTT样本值,但以后每次测量到一个新的RTT样本,就按下面的公式重新计算一次RTTs:
新的RTTs=(1-α)×(旧的RTTs)+α×(新的RTT样本)
在上式中:(阿尔法 的值介于0到1,若很接近0,则表示旧的RTTs值和新的RTTs值相比变化不大,也就是说,新的RTT样本不太影响RTTs; 若很接近1,则表明新的RTTs值,受当前采集的RTT样本影响较大,跟上次的RTTs差距大)
RFC 2988:推荐的α(阿尔法)值为1/8,也就是0.125 (这种方式得出的值更为平滑)
显然:超时计数器设置的超时重传时间RTO(Retransmission Time-Out)应略大于上面计算的结果。同样的:
RFC 2988:建议使用下面的公式计算RTO:
RTO=RTTs+4×RTTd
RTTd是RTT的偏差的加权平均值,与RTTs和新的RTT样本之差有关。RFC 2988建议这样计算RTTd。当第一次测量时,RTTd值取为RTT样本值的一半。在以后的测量中,则使用下式计算加权平均RTTd:
新的RTTd=(1-β)×(旧的RTTd)+ β × | 新的RTT样本-RTTs |
这里的β(贝塔)是一个小于1的系数,它的推荐值是1/4,即就是0.25
好了,通过上面这些东西:我们就可以求出超时计数器所要设置的时间问题了,但是,但是,但是,新的问题也来了?
发送一个报文段,设定的重传时间到了,还没有收到确认。于是重传报文段,经过一段时间后:收到了确认报文段。
现在的问题是:如何判定此报文段是对先发送的报文段的确认,还是对后来重传的报文段的确认???由于重传的报文段和原来的报文段完全一样,所以源主机在接受到确认后,无法做出正确的判断,而正确的判断对确定加权平均RTTs的值关系很大。
1,若收到的是对重传报文段的确认,但却被源主机当作是对原来报文段的确认,则计算出的RTTs和超时重传时间RTO就会偏大。若后面再发送的报文段又是经过重传后才收到的确认报文段,则RTO这个时间会越来越长。直接影响效率
2,若收到的是对原来的报文段的确认,但被当作是对重传报文段的确认,则由此计算出的RTTs和RTO都会偏小,这样就会导致过多的重传,使的RTO越来越小
根据以上所说:Karn提出了一个算法:在计算加权平均RTTs时,只要报文段重传了,就不采用其往返时间样本。这样得出的加权平均RTTs和RTO就相对比较准确了。
但是,但是,要是出现这样的情况呢??:报文段的时延突然增大了很多。因此在原来得出的重传时间内,不会收到确认报文段。于是就重传报文段。但根据Karn算法,不考虑重传的报文段的往返时间样本。这样:超时重传时间就无法更新。
因此:要对Karn算法进行修正:方法是:报文段每重传一次,就把超时冲传时间RTO增大一些。典型的做法是:取新的重传时间为2倍的旧的重传时间。当不再发生报文段的重传时,才根据上面给出公式计算超时重传时间。