TCP中用于计算重传时间RTO的数据结构定义在tcp协议控制块中。
struct tcpcb {
.......
/*动态计算的数据包发送确认的往返时间*/
short t_rtt; /* round trip time */
/*标记设定了重传定时器的报文的开始序号*/
tcp_seq t_rtseq; /* sequence number being timed */
/*已平滑的rtt*/
short t_srtt; /* smoothed round-trip time */
/*已平滑的RTT的平均偏差估计器*/
short t_rttvar; /* variance in round-trip time */
/*重传时限最小值*/
u_short t_rttmin; /* minimum rtt allowed */
short t_rxtshift; /* log(2) of rexmt exp. backoff */
/*当前的重传时间*/
short t_rxtcur; /* current retransmit value */
/*指数退避的数组索引*/
u_long max_sndwnd; /* largest window peer has offered */
......
}
T C P的一个基本操作是在发送了需对端确认的报文段后,设置重传定时器。如果在定时器时限范围内未收到A C K,该报文段被重发。T C P要求对端确认所有数据报文段,不携带数据的报文段则无需确认(例如纯A C K报文段)。如果估算的重传时间过小,响应到达前即超时,造成不必要的重传;如果过大,在报文段丢失之后,发送重传报文段之前将等待一段额外的时间,降低了系统的效率。更为复杂的是,主机间的往返时间动态改变,且变化范围显著。
T C P计算重传时限( RTO )时不仅要测量数据报文段的往返时间RTT(nticks),还要记录已平滑的RT T估计器(srtt)和已平滑的RT T平均偏差估计器(rttvar)。平均偏差是标准方差的良好近似,计算较为容易,无需标准方差的求平方根运算。
d e l t a = n t i c k s-s rt t
s rt t←s rt t + g×d e l t a
rt t v a r←rt t v a r + h(| d e l t a |-rt t v a r)
RTO = s rt t +4×rt t v a r
d e l t a是最新测量的往返时间(n t i c k s)与当前已平滑的RT T估计器(s rt t)间的差值;
g是用到RT T估计器的增益,设为1 / 8;
h是用到平均偏差估计器的增益,设为1 / 4。
这两个增益和RTO计算中的乘数4有意取为2的乘方,从而无需乘、除法,只需简单的移位操作就能够完成运算。
void
tcp_xmit_timer(tp, rtt)
register struct tcpcb *tp;
short rtt;
{
register short delta;
tcpstat.tcps_rttupdated++;
if (tp->t_srtt != 0) {
/*
* srtt is stored as fixed point with 3 bits after the
* binary point (i.e., scaled by 8). The following magic
* is equivalent to the smoothing algorithm in rfc793 with
* an alpha of .875 (srtt = rtt/8 + srtt*7/8 in fixed
* point). Adjust rtt to origin 0.
*/
更新已平滑的RT T估计器
delta = rtt - 1 - (tp->t_srtt >> TCP_RTT_SHIFT);
tcpnewtcpcb初始化已平滑的RTT估计器(tsrtt)为0,指明连接上不存在RTT估计器。delta是RTT测量值与当前已平滑的RTT估计器间的差值,以未缩放的滴答为单位。t s r t t除以8,单位从缩放后的滴答转换为未缩放的滴答。
if ((tp->t_srtt += delta) <= 0)
tp->t_srtt = 1;
已平滑的RT T估计器用以下公式进行更新:
s rt t←s rt t+ g×d e l t a
由于增益g = 1 / 8,公式变为
8×s rt t←8×s rt t+ d e l t a
也就是
t s r t t←t s r t t+d e l t a
/*
* We accumulate a smoothed rtt variance (actually, a
* smoothed mean difference), then set the retransmit
* timer to smoothed rtt + 4 times the smoothed variance.
* rttvar is stored as fixed point with 2 bits after the
* binary point (scaled by 4). The following is
* equivalent to rfc793 smoothing with an alpha of .75
* (rttvar = rttvar*3/4 + |delta| / 4). This replaces
* rfc793's wired-in beta.
*/
已平滑的RT T平均偏差估计器
if (delta < 0)
delta = -delta;
delta -= (tp->t_rttvar >> TCP_RTTVAR_SHIFT);
if ((tp->t_rttvar += delta) <= 0)
tp->t_rttvar = 1;
} else {
第一次估计SRTT
/*
如果是首次测量某连接的RT T值,已平滑的RT T估计器初始化为测量得到的样
本值。
* No rtt measurement yet - use the unsmoothed rtt.
* Set the variance to half the rtt (so our first
* retransmit happens at 3*rtt).
*/
tp->t_srtt = rtt << TCP_RTT_SHIFT;
平均偏差等于测量到的RT T值的一半
tp->t_rttvar = rtt << (TCP_RTTVAR_SHIFT - 1);
}
下一个报文的发送和计时做准备
tp->t_rtt = 0;
tp->t_rxtshift = 0;
RT T计数器(trtt)和重传移位计数器(trxtshift)同时复位为0,为下一个报文的发送和计时做准备
/*
* the retransmit should happen at rtt + 4 * rttvar.
* Because of the way we do the smoothing, srtt and rttvar
* will each average +1/2 tick of bias. When we compute
* the retransmit timer, we want 1/2 tick of rounding and
* 1 extra tick because of +-1/2 tick uncertainty in the
* firing of the timer. The bias will give us exactly the
* 1.5 tick we need. But, because the bias is
* statistical, we have to test that we don't drop below
* the minimum feasible timer (which is 2 ticks).
*/
连接的下一个RTO(t_rxtcur)计算
TCPT_RANGESET(tp->t_rxtcur, TCP_REXMTVAL(tp),
tp->t_rttmin, TCPTV_REXMTMAX);
#define TCP_REXMTVAL(tp) \
(((tp)->t_srtt >> TCP_RTT_SHIFT) + (tp)->t_ttvar)
其实,这就是我们很熟悉的公式
RTO=s rt t+ 4×rt t v a r
/*
* We received an ack for a packet that wasn't retransmitted;
* it is probably safe to discard any error indications we've
* received recently. This isn't quite right, but close enough
* for now (a route might have failed after we sent a segment,
* and the return path might not be symmetrical).
*/
tp->t_softerror = 0;
}