zoukankan      html  css  js  c++  java
  • TCP之超时和重传

    RTT:往返时间;  RTO:Retransmission Timeout即超时重传时间;

    关键点在于:超时和重传间隔的策略,即怎样确定超时间隔和重传间隔;

      TCP中的四个定时器:2MSL定时器;重传定时器;坚持定时器;保活定时器;

    首先是如何得到RTO值;(假设已经能测量到RTT值情况下)

      RTO值是依赖RTT值来确定的;而鉴于网络环境的不稳定性,RTT总是变化的,

      RTT = 0.1*M  + 0.9*R;  M:当前测试的RTT值,R:历史RTT的值;

      RTO=@RTT;        @:一般取2;

    详解过程参见RFC793,但是该方法是有缺陷的;

    新的方法:

      Err = M - A;  M:当前RTT值, A:历史RTT值;

      平均值:A = A+gErr;  A:历史RTT值, g:常量, 

      方差:D = D + h(|Err| - D); D:历史D的值,h:常量

     (重点):RTO = A + 4D;

    RTO的初始化: A=0; D=3;(即没有测的RTT情况下)

    RTO的更新

    当数据正常传输的情况下,我们就会用上面的公式来更新各个数据,并重开定时器,来保证下一个数据被顺利传输。要注意的是:重传的情况下,RTO不用上面的公式计算,而采用一种叫做“指数退避”的方式。例如:当RTO为1S的情况下,发生了数据重传,我们就用RTO=2S的定时器来重新传输数据,下一次用4S。一直增加到64S为止。

    (也就是说:1、计时器计算是否超时是用的是几乎时时更新的RTO(估计器)时间,而重传时间间隔采用的是“指数退避(exponential backoff)“时间,

          2、并且在重传的情况下,不更新估计器的各种参数,

    上述两点就是所谓的 Karn算法

    );

    估计器的更新:

    1. 一个连接中,有且仅有一个测量定时器被使用。也就是说,如果TCP连续发出3组数据,只有一组数据会被测量。
    2. ACK数据报不会被测量,原因很简单,没有ACK的ACK回应可以供结束定时器测量

    示例: 

     1、传SYN:

        传输初始SYN所使用的RTO:RTO = A + 2D = 6s; (这个公式以后不再用了)

      2、上述SYN丢失了;然后超时了;因为6s内没有收到ACK;

        计算当前的RTO: RTO=A + 4D = 0 + 4×3 = 12s

      由于这是第一次超时,我们使用的倍数是2^0;RTO = 2^0*12 = 12s

    拥塞避免算法与慢启动算法的结合:

      原因:数据在传输的时候不能只使用一个窗口协议,我们还需要有一个拥塞窗口来控制数据的流量,使得数据不会一下子都跑到网路中引起“拥塞”。曾经提到过,拥塞窗口最初使用指数增长的速度来增加自身的窗口,直到发生超时重传,再进行一次微调。但是没有提到,如何进行微调,拥塞避免算法和慢启动门限就是为此而生。

      拥塞避免算法和慢启动算法需要对每个连接维持两个变量:

        一个拥塞窗口cwnd,  和 一个慢启动门限ssthresh;它们的工作过程如下:

      1、对一个给定的连接,初始化cwnd为1个报文段,ssthresh为2^16=65535个字节;

      2、此时TCP输出的报文段不能超过cwnd和接收方通告窗口的大小,拥塞避免是c方使用的流量控制,通告窗口则是s方进行的流量控制,

        拥塞避免是c方感受到网络拥塞的估计;通告窗口与s方在该连接上的缓存大小有关;

      3、当拥塞发生时(超时或者收到重复的ACK;都表明丢包了), ssthresh被设置为当前窗口大小的一半(当前窗口即cwnd和通告窗口两者中的小值,但最少为2个报文段),

        如果是超时引起的拥塞,则cwnd被设置为1个报文段(这就是慢启动)

      4、当新的数据被对方确认时,就增加cwnd,但增加的方法依赖于我们是否正在进行慢启 动或拥塞避免。如果cwnd小于或等于ssthresh,则正在进行慢启动,否则正在进行拥塞避免。 慢启动一直持续到    我们回到当拥塞发生时所处位置的半时候才停止(因为我们记录了在步骤2 中给我们制造麻烦的窗口大小的一半),然后转为执行拥塞避免。

    快速重传和快速恢复算法

    这是数据丢包的情况下给出的一种修补机制。一般来说,重传发生在超时之后,但是如果发送端接受到3个以上的重复ACK的情况下,就应该意识到,数据丢了,需要重新传递。这个机制是不需要等到重传定时器溢出的,所以叫做快速重传,而重新传递以后,因为走的不是慢启动而是拥塞避免算法,所以这又叫做快速恢复算法。流程如下:

    1. 当收到第3个重复的ACK时,将ssthresh设置为当前拥塞窗口cwnd的一半。重传丢失的 报文段。设置cwnd为ssthresh加上3倍的报文段大小。
    2. 每次收到另一个重复的ACK时, cwnd增加1个报文段大小并发送1个分组(如果新的 cwnd允许发送)。
    3. 当下一个确认新数据的ACK到达时,设置cwnd为ssthresh(在第1步中设置的值)。这个 ACK应该是在进行重传后的一个往返时间内对步骤1中重传的确认。另外,这个ACK也应该 是对丢失的分组和收到的第1个重复的ACK之间的所有中间报文段的确认。这一步采用的是拥 塞避免,因为当分组丢失时我们将当前的速率减半

    ICMP会引起重新传递么?

    答案是:不会,TCP会坚持用自己的定时器,但是TCP会保留下ICMP的错误并且通知用户。

    重新分组

    TCP为了提高自己的效率,允许再重新传输的时候,只要传输包含重传数据报文的报文就可以,而不用只重传需要传输的报文。

      

  • 相关阅读:
    websocket在线测试工具
    短信线上发送错误,线下成功
    nginx添加stream模块1.20
    sort 的使用
    实验、进程的同步与互斥——生产者消费者
    实验、可变分区存储管理系统模拟 —— 最先适应分配算法
    test
    c++的大数阶乘算法
    C#解析JSON字符串总结
    C++ 查看单个类对象模型利用Vs开发者命令提示工具
  • 原文地址:https://www.cnblogs.com/chris-cp/p/3893103.html
Copyright © 2011-2022 走看看