超时重传时间的选择
前文提到,TCP的发送方在规定的时间内没有收到确认就要重传已发送的报文段,由于TCP的下层是互联网环境,发送的报文段可能只经过一个高速率的局域网,也可能经过多个低速率的网络,并且每个IP数据报所选择的路由还可能不同。如果把超时重传时间设置得太短,就会引起很多报文段的不必要的重传,使网络负荷增大。但若把超时重传时间设置得过长,则又使网络的空闲时间增大,降低了传输效率。
那么,运输层的超时计时器的超时重传时间究竟应设置为多大呢?
TCP采用了一种自适应算法,它记录一个报文段发出的时间,以及收到相应的确认的时间。这两个时间之差就是报文段的往返时间RTT。TCP保留了RTT的一个加权平均往返时间RTTS。当第一次测量到RTT样本时,RTTS就取为所测量到的RTT样本,但以后每测量到一个新的RTT样本,就按下式重新计算一次RTTS:
在上式中, 0 ≤ α < 1。若 α 很接近于零,表示新的RTTS值和旧的RTTS值相比变化不大,而对新的RTT样本影响不大。若 α 接近于1,则表示新的RTTS值受新的RTT样本的影响较大。已成为建议标准的RFC 6298 推荐 α 值为 0.125。
显然,超时重传时间 RTO 应略大于上面得出的加权平均往返时间RTTS。RFC 6298 建议使用下式计算 RTO:
RTTD是RTT的偏差的加权平均值。它与RTTS和新的RTT样本之差有关。RFC 6298 建议这样计算RTTD。当第一次测量时,RTTD 值取为测量到的RTT样本值的一半。在以后的测量中,则使用下式计算加权平均的RTTD:
β是一个小于1的系数,它的推荐值是0.25。
选择确认SACK
若收到的报文段无差错,只是未按序号,中间还缺少一些序号的数据,那么能否设法只传送缺少的数据而不重传已经正确到达接收方的数据?答案是可以的,选择确认就是一种可行的处理方法。
如下图所示,TCP的接收方接收对方发送过来的数据字节流的序号不连续,结果形成了一些不连续的字节快。可以看出,序号11000收到了,但序号10011500没有收到。接下来的字节流又收到了,可是又缺少了3001~3500,从序号4501起又没有收到。也就是说,接收方收到了和前面的字节流不连续的两个字节块。如果这些字节的序号都在接收窗口内,那么接收方就先收下这些数据,但要把这些信息准确的告诉发送方,使发送方不要再重复发送这些已收到的数据。
从上图可以看出,和前后字节不连续的每一个字节块都有两个边界:左边界和右边界。左边界指出字节块的第一个字节的序号,右边界减一指出了字节块的最后一个序号。TCP的首部没有哪个字段能够提供上述这些字节块的边界信息。RFC 2018 规定,如果要使用选择确认SACK,那么在建立TCP连接时,就要在TCP首部的选项中加上“允许SACK”的选项,双方必须事先商定好。如果使用选择确认,那么原来首部中的“确认号字段”的用法依然不变。只是以后在TCP报文段的首部中都增加了SACK选项,以便报告收到的不连续的字节块的边界。由于首部选项的长度最多只有40字节,而指明一个边界就要用掉4字节(序号32位),指明一个字节块需要8个字节,还需要留出两个字节,一个字节用来指明是SACK选项,另一个字节指明这个选项要占用多少字节,所以选项中最多指明4个字节块的边界信息。
然而,SACK文档并没有指明发送方应当怎样响应SACK。因此大多数的实现还是重传所有未被确认的数据块。