从上一篇示例中我们可以看到在TCP中有一个重要的过程就是决定何时进行超时重传,也就是RTO的计算更新。由于网络状况可能会受到路由变化、网络负载等因素的影响,因此RTO也必须跟随网络状况动态更新。如果TCP过早重传,则可能会向网络中注入很多重复报文,如果过晚重传,则在丢包时候则会影响滑窗前行可能会降低网络利用率。因为TCP在接收到数据后会发送累计的ACK number,因此TCP发送某个系列号的报文后,在接收到覆盖此系列号的ACK报文的时候,测量发送和接收之间的时间,这个测量就叫做RTT采样(RTT sample)。TCP对于每个连接都会根据RTT采样来维护跟新RTO,同时还会维护一个RTO超时的定时器。注意是对每个连接维护一个超时定时器,而不是对每个发出去的TCP报文。当TCP发出数据报文(或者SYN、FIN报文)的时候,如果之前没有等待ACK的报文则会设置这个连接的RTO定时器,如果之前有等待ACK的报文,则并不会重启RTO定时器。当TCP同时有多个报文发出且没有等到ACK的时候,则会先重传第一个报文,第一个报文重传成功收到ACK后,再设置RTO定时器然后重传第二个报文。
本篇先来介绍一下协议中更新计算RTO的方法。协议中主要有两种方法来计算RTO一种是RFC793的经典方法(classic method),另一种是RFC6298的标准方法(standard method)。
一、经典方法
在原始的RFC793中关于RTO更新的介绍只有半页文字的样子,它首先让TCP使用下面的公式更新一个平滑RTT估计(smoothed RTT estimator、简称SRTT):
SRTT = ( ALPHA * SRTT ) + ((1-ALPHA) * RTT)
其中RTT是之前介绍的一个RTT采样值,ALPHA则是一个平滑因子(smoothing factor),协议给出的示例范围是0.8--0.9之间。这个过程也叫做指数加权移动平均(exponentially weighted moving average、简称EWMA)。可以看到这个计算过程只需要保留一个RTT采样值就行了,而不需要保留过多的历史RTT采样。
接着在按照下面公式计算出RTO:
RTO = min[UBOUND,max[LBOUND,(BETA*SRTT)]]
其中BETA是一个延迟因子,协议给出的示例范围是1.3--2.0。UBOUND是一个RTO上限,LBOUND是一个RTO下限,UBOUND和LBOUND协议给出的示例范围分别是1分钟和1秒,显然这两个值对于现代TCP网络可能并不合适。
二、标准方法
RFC1122指出上面介绍的计算RTT的经典方法中存在两个问题,一个是在发生TCP重传的时候,RTT采样的精确测量非常困难,第二个问题是经典方法认为RTT是比较平稳