我们直到,重传机制是 TCP 协议中一种重要的通信保障手段。在超时重传下,当重传计时器超过 RTO (Retransmission Time Out) 时就会终止计时器并重发。而其中 RTO 是基于 RTT (Round-Trip Time)得到的,那么 RTT 又是如何得到的呢?似乎看起来很简单,好像就是在发送端发包时记下 T_0 ,接收到 ACK 报时再记一个 T_1 ,于是 RTT = T_1 – T_0 。没那么简单,这只是一个采样,不能代表普遍情况。

Jacobson / Karels 算法

  1. 我们需要采样一些 RTT,称为 SampleRTT 。需要注意, SampleRTT 与单个分组没有一一对应的关系,由于 延迟确认 的存在,两个确认可能合并为一个 ACK 包。SampleRTT 可能随网络情况而波动,任何值都可能是不典型的,所以直接使用 SampleRTT 是不可靠的。

  2. 为了估计一个典型的 RTT,自然想到对 SampleRTT 求平均(加权平均),得到平滑RTT(RTT_S ,计算方法如下:
    RTT_S = (1 - α)RTT_S+α×SampleRTT

    其中 α 取决于实现,一般为 0.125

  3. 另外,还需要引入 RTT偏差(DeviationRTT),即 RTT_D ,其计算依赖于 RTT_S 和 SampleRTT:

    RTT_D=(1-β)×RTT_D+β×|RTT_S-SampleRTT|

    其中 β 取决于实现,一般为 0.25

  4. 最后根据 RTT 计算 RTO:

    RTO=RTT_S+4×RTT_D

上面的叙述为了流畅性省略了一些内容,下面是全过程:

RTO计算过程

下面给出一个例子:当 SNY+ACK 段传来时,SampleRTT 被测量为 1.5 秒,计算 RTO:

  1. SampleRTT=1.5
  2. RTT_S=1.5
  3. RTT_D=1.5/2=0.75
  4. RTO=1.5+4×0.75

平均 RTT 一般定为 0.25 秒;同时需要注意,RTT 指的是传播时延而非传输时延RFC 6298 推荐的初始 RTO 为 1 秒。

Karn算法

重传计时器超时会重发报文。而上面的这个算法对于重传会遇到这样一个问题:当发送方收到来自接收方的 ACK 段时,如何判别这个段是第一次发的还是重传的?即使知道,也会面临如下问题:你是用第一次发数据的时间和 ACK 回来的时间做 RTT 样本值,还是用重传的时间和 ACK 回来的时间做 RTT 样本值?

示意图
  • 情况(a)是 ACK 没回来,所以重传。如果你计算第一次发送和 ACK 的时间,那么,明显算大了。
  • 情况(b)是 ACK 回来慢了,但是导致了重传,但刚重传不一会儿,之前 ACK 就回来了。如果你是算重传的时间和 ACK 回来的时间的差,就会算短了。

Karn 算法简单粗暴地解决了此问题——当需要重传时,则不采用此报文来测量 RTT,等到发送方不需要重发某个段时,再进行采样 。但是,这样一来,又会引发一个新问题——如果在某一时间,网络闪动,突然变慢了,产生了比较大的延时,这个延时导致要重传所有的包。由于重转的不采样,RTO 就不会被更新,这导致网络实时状况被发送端忽略(发送方就无法合理调整后续发送行为),可能加重网络拥塞。Karn 算法据此提出 指数回退 ,当发生重传时,则 RTO 翻倍。例如重传一次后 RTO = 2 s,还未收到,再重传一次,RTO = 4 s …
即,Karn 算法规定两点:1)碰上重传则不采样;2)碰上重传则 RTO 翻倍。

时间戳测量RTT

详解笔者的另一篇文章:时间戳RTTM

文章参考:《计算机网络自顶向下第六版》 ,《计算机自顶向下第七版》 ,TCP 14即时通讯网

文章作者: 极简
本文链接:
版权声明: 本站所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 后端技术分享
网络理论
喜欢就支持一下吧