TCP协议:超时重传机制
超时重传的原理是在发送某一个数据以后就开启一个计时器,在一定时间内如果没有得到发送的数据报的ACK报文,那么就重新发送数据,直到发送成功为止。
引入两个概念:
- RTT(Round Trip Time):往返时延,也就是数据包从发出去到收到对应ACK的时间。RTT是针对连接的,每一个连接都有各自独立的RTT。
- RTO(Retransmission Time Out):重传超时时间,TCP发送方在没有收到某个数据段的ACK时,需要等待多长时间才能进行重传。
如何合理设置RTO是超时重传的关键:
- 如果RTO过大,降低网络吞吐量,增加延迟;
- 如果RTO过小,会造成不必要的重传;
因为网络是动态变化的,RTT会动态变化,因此RTO时间也会动态变化。
RTO的计算
1.计算SRTT
TCP的RTT计算采用加权移动平均算法,这个方法能够平滑地反映网络延迟的波动。
- 取样:当一个TCP段发送后,计时器开始。当收到对应的ACK后,计时器停止,得到一个SampleRTT(本次测量的RTT)
- 
    平滑RTT(Smoothed RTT, SRTT):这是对所有SampleRTT的加权平均,反映了平均网络延迟。计算如下: \[SRTT=(1−α)⋅SRTT+α⋅SampleRTT\]其中,α是一个平滑因子,通常取值为 1/8(即0.125)。这意味着新的SampleRTT对SRTT的影响较小,使得SRTT更加稳定。 
2.计算RTT偏差
RTT偏差(RTT Variation, RTTVAR)用来衡量SampleRTT与SRTT之间的差异,反映了网络延迟的波动程度。 计算如下:
\[RTTVAR=(1−β)⋅RTTVAR+β⋅|SampleRTT−SRTT|\]其中,β通常取值为1/4(即0.25)。这使得RTTVAR对新的SampleRTT变化较为敏感。
3.计算RTO
RTO基于SRTT和RTTVAR来动态调整,确保在网络状况变化时能够适应。计算如下:
\[RTO=SRTT+max(G, K⋅RTTVAR)\]其中:
- G是一个小的常数(通常为1秒),用于防止RTO过小;
- K通常取值为4。
这个公式的含义是:RTO等于平均往返时间SRTT加上4倍的RTTVAR,以此来覆盖大部分的网络延迟波动,减少不必要的重传。
Karn算法
重传二义性
如果在一个报文段中的数据被一次性地成功传输和确认,那么发送端可以准确得到该报文段传输的SampleRTT。
但若出现了重传,情况就会变得很复杂。例如,一个包发送后出现超时,该数据包会进行重传。当收到这个包的ACK后,发送方无法区分这个ACK是对第一次还是第二次传输的确认。因为这两个报文段产生的确认信息是完全相同的,确认信息既可能是针对原始报文段的,也可能是对重传报文段的确认。
确认的二义性将导致TCP无法准确地估算RTT。
Karn算法
为了解决这个问题,Karn算法提出了一条简单的原则:
- 任何由重传产生的数据包,其SampleRTT都不能被用于计算SRTT和RTTVAR。
Karn算法认为,只有非重传的数据包所返回的ACK才能作为RTT采样的有效数据。
RTO的指数退避
重传通常表明网络状况不佳,很可能是由网络拥塞引起,如果发送端持续重传,则会使得拥塞越来越严重。
因此,Karn算法建议在每次重传后,RTO应进行指数退避(Exponential Backoff)处理:
- 当一个数据包被重传时,Karn算法建议将RTO翻倍。
通过增加RTO,Karn算法为网络提供了更多的恢复时间,减少了进一步拥塞的风险。
Karn算法的改进
Karn算法解决了重传歧义问题,但它也有一个明显的缺陷:
- 当网络出现持续拥塞时,RTO会因为指数退避而不断增大。
- 由于没有新的RTT样本,SRTT和RTTVAR无法得到更新。这可能导致RTO变得过大。
- 即使网络拥塞已经缓解,RTO也无法快速适应,从而降低了TCP的吞吐量。
为了弥补Karn算法的不足,TCP引入了Timestamps选项。当启用该选项时,发送方会在每个TCP段中包含一个时间戳。接收方在返回的ACK中也会携带这个时间戳。这样,发送方就可以通过对比时间戳来准确地计算出RTT,即使数据包发生了重传,也能判断出这个ACK是对应于哪一次发送的。
现代TCP协议通常都支持并使用时间戳来更精确地计算RTT和RTO。