• TCP/IP的确认号,序列号和超时重传的学习笔记


    一:确认应答和序列号

    在tcp中,发送端的数据到达主机时,接收端会返回一个已收到的通知。这个消息叫做确认应答(ACK)。

    当发送端发送数据后,会等待对端的确认应答。如果有确认应答,说明数据已经成功到达。反之,则数据丢失的可能性很大。

    发送端一定时间内没有等到确认应答,发送端就认为数据已经丢失了,就可以重发数据。因此,即使产生了丢包,也能保证数据到达对端。实现可靠传输。

    想一下:为什么发送端一定时间内没有收到确认应答呢?有哪些原因呢?

    这里有几个对象:

    1、发送端,发送的数据

    2、对端,回应的ACK数据

    3、中间的网络

    第一种 发送端:发送端的数据根本没有到达对端,发送的数据在途中就已经丢失了。

    第二种 对端:可能数据对方已经收到了,只是回应ACK的数据时,途中丢失了。这种情况会导致发送端没有收到对端的确认应答。

    第三种:网络:由于网络拥堵,确认应答ACK延迟到达了。或者发送端的数据延迟到达对端了。这种情况也可能导致重发数据包。

    上面这些情况都有可能导致发送端没有收到对端的ACK应答。

    上面说了, 如果需要发送端重发数据,那需要重发哪部分数据,发送端怎么知道重发哪部分数据?

    这个就是序列号功能了。

    什么是序列号:

    序列号是按照顺序给发送数据的每一个字节都编号。

    接收端接收数据TCP首部中的序列号和数据长度,将自己下一步接收的序号作为确认应答发送回去。

    这样,通过序列号和确认应答号,就可以实现TCP的可靠传输。

    上面谈到了重发数据情况,那什么时候重发数据呢? 这个时间怎么计算?
    也就是说,这个重发的时间怎么确定?什么时候开始计时的?

    二:重发和重发超时时间

    重传定时器

    要实现超时重发,就是在发送完一组数据时,就立即给这组数据设置一个超时定时器。如果定时器到期之前收到了对端的确认号,就撤销重传超时定时器。

    超时时间怎么设置:

    • 如果设置的长一点,重发数据就变慢了,效率就变差了;
    • 如果设置的短一点,可能会导致数据还没丢就重发了。这样的话,重发数据就变快了,自然会增加网络负担,导致网络拥塞,一拥塞,就会导致更多的超时,超时又导致更多的重发。

    所以这个时间的设置就变得很重要了。

    先看看发送数据的几个步骤:

    1. 发送端发送数据,并启动重传定时器
    2. 等待对端的应答ACK号
    3. 重传定时器到期

    这里有几个时间的概念:

    1. RTT(Round Trip Time):发送一个数据包到收到对端的ACK所花费的时间
    2. RTO(Retransmission TimeOut): 发送数据包,启动重传定时器,重传定时器到期所花费的时间,称为RTO

    网络又是复杂的,由各种主机,路由器,网络等组成。所以这个重传时间RTO只能动态来计算了。
    经过一些计算机专家的研究,它是根据RTT来动态计算的。

    重传时间算法

    第一种经典算法:RFC793

    1. 首先计算一个平滑的RTT称为SRTT, alpha是一个平滑因子,取值为0.8或者0.9
    SRTT = ( ALPHA * SRTT ) + ((1-ALPHA) * RTT)
    
    1. 基于SRTT,计算出对应的RTO
    RTO = min[UBOUND, max[LBOUND, (BETA*SRTT)]
    

    其中UBOUND是最大值,一般情况下为120s,LBOUND是最小重传值,一般情况下为1s,Beta也是一个因子,建议取值为1.3~2.0.
    这个算法来自 RFC793

    但是这个算法在目标Linux中没有使用,原因是存在不足。有文章指出:从公式可以看到在经典的RTO计算方法中会有一个很大的问题,就是当RTT对RTO的影响太小了,也就是说经典的RTO计算方法在RTT变化比较大的网络中,会表现的非常不好的。

    第二种算法:Jacobaon/Karels 算法

    1988年,Van Jacobson和Karels在Congestion Avoidance and Control这篇论文中提出一种新的算法RFC6298,这里对于rtt的采样,多添加了一个因素,那就是均差(mean deviation),而这里并不是传统意义上的均差,使用的平均数其实就是我们在经典方法中的srtt。

    第一次RTO计算方法, 假设RTT = R

    1. SRTT = R
    
    2. RTTVAR = R/2
    
    3. RTO = SRTT + max(G, K*RTTVAR) , K = 4
    

    后续的RTO计算,假设当前的RTT为R'

    RTTVAR = (1 - beta)*RTTVAR + beta*|SRTT - R'|
    //计算平滑RTT和真实RTT的差距,切记这个地方的SRTT是上一次的SRTT
    
    SRTT = (1 - alpha)*SRTT + alpha*R'
    //计算平滑RTT, 及是SRTT
    
    RTO = SRTT + max(G, K*RTTVAR)
    //计算 RTO
    

    alpha = 1/8  beta = 1/4,值得指出的是这个算法在目前的Linux协议栈中应用

    第二种算法到底有啥好处,可以去查看相关文章看看

    参考

  • 相关阅读:
    spring 配置版本问题
    sublime与Emment
    工欲善其事必先利其器之浏览器篇
    工欲善其事必先利其器之windows篇
    工欲善其事必先利其器之搜索引擎
    营销自我
    java必备技能
    离线安装ADT和sdk
    eclipse的小技巧
    匿名内部类
  • 原文地址:https://www.cnblogs.com/jiujuan/p/12203836.html
Copyright © 2020-2023  润新知