前面已经讲到,TCP的发送方式在规定的时间内没有收到确认就要重传已发送的报文段。这种重传的概念是很简单的,但重传时间的应该设置多少合适呢?这是TCP最复杂的问题之一
如果把超时重传时间设置的过长,就会引起很多报文段不必要的重传,使网络负荷增大。但若把超时重传时间设置的过长,则又使网络的空闲时间增大,降低了传输效率。
TCP采用了一种自适应算法,它记录一个报文段发出得到时间,以及收到相应的确认的时间,这两个时间之差就是报文段的往返时间RTT(又称为平滑往返时间)。TCP保留了RTT的一个加权平均往返时间RTTs。每当第一次测量到RTT样本时,RTTs值就取为所测量到的RTT样本值。但以后每测量到一个新的RTT样本,就按下列的公式重新计算一次RTTs:
在上式中,0<=<1。若
很接近于0,表示新的RTTs值和旧的RTTs值相比变化不大,对新的RTT样本影响不大。若选择
接近于1,则表示新的RTTs值受新的RTT样本的影响较大。RFC6298推荐的
值为1/8,即0.125.用这种方法得出加权平均往返时间RTTs就比测量出的RTT值更加平滑。
显然,超时计数器设置的超时重传时间RTO应该略大于上面得出的加权平均往返时间RTTs,计算公式如下:
而RTTd是RTT的偏差的加权平均值,它与RTTs和新的RTT样本之差有关。计算方法是,当第一次测量时,RTTd值取为测量到的RTT样本值的一半,计算公式如下:
这里的是小于1的系数,它的推荐值是1/4.即0.25.
举例:
发送出一个报文段,设定的重传时间到了,还没有收到确认。于是重传报文段,经过一段时间后,收到了确认报文段。现在的问题是:如何判定此报文段是先对先发送的报文段的确认,还是对重传的报文段的确认。
由于重传的报文段和原来的报文段完全一样,因此源主机收到确认后,就无法做出正确的判断,而由上图可见,如何判断对确定加权平均RTTs的值关系很大。
若收到的确认是对重传报文段的确认,但却被接收端当成是对原来的报文段的确认,则这样计算出的RTTs和超时重传时间RTO就会偏大。若后边再发送的报文段又是经过重传后才收到确认报文段,则按此方法得出的超时重传时间RTO就越来越长。
同样,若收到的确认是对原来的报文段的确认,但被当成是对重传报文段的确认,则由此计算出RTTs和RTO都会偏小,这就必然导致报文段过多的重传,这样就有可能使RTO越来越短。
于是:TCP采用的解决方法是当发生重传时,每重传一次,就把超时重传时间RTO增大为原来的二倍;当不发生报文段的重传时,就根据上边的公式来计算。
起初的解决办法是Karn提出来的:在计算加权平均RTTS时,只要报文段重传了,就不采用其往返时间样本。但是此方法存在一个问题:如果不采用往返时间样本,那么超时重传时间就无法更新。如果采用又会出现上述的问题,所以才有了折中的办法。
选择确认SACK
选择确认是对那些不连续到达的数据所采取的措施,也就是说接收方收到了和前面的字节流不连续的两个字节快,如果这些字节的序号都在接收窗口之内,那么接收方就先收下这些数据,但是要把这些信息准确地告诉发送方,使发送方不要再重复发送这些已经收到的数据。