TCP重传与超时(Linux)

重传次数

    **tcp通过设置R1值来确定:**愿意尝试重传多少次之后,向IP层传递重新评估当前的IP路径。

    **tcp通过设置R2值来确定:**愿意尝试重传多少次之后,放弃当前连接。

    Linux通过分别设置**net.ipv4.tcp\_retries1**和**net.ipv4.tcp\_retries2**来设置**R1**和**R2**值。

    对于建立连接的**SYN**与**SYN\_ACK**重传次数,Linux通过分别设置**net.ipv4.tcp\_syn\_retries**和**net.ipv4.tcp\_synack\_retries**来设置。

带TSOPT(Time Stamp)选项的RTO计算

    **rto(Retransmission TimeOut):**超时重传时间。

    **rtt(Round-Trip Time):**发送端发送包到接收端,接收端再返回ack到发送端的往返时间。

    **srtt(Smoothed Round-Trip Time):**平滑的[rtt](https://so.youkuaiyun.com/so/search?q=rtt&spm=1001.2101.3001.7020)。

    **mdev(Mean Deviation):**瞬时偏差。

    **mdev\_max:**瞬时偏差最大值。

    **m:**RTT样本。

    **last\_ack:**接收端的记录,接收端最后一次发送ack的ack序号。  
    **tsv:**发送端发给接收端的包中TSOPT选项中的数据。

    **ts\_recent:**接收端的记录,接收端最前一个未回复ack的包所带的tsv的副本。

    **tser:**接收端回复发送端的包中TSOPT选项中的数据。

    **tcp\_rto\_min:**最少rto

    **tcp\_rto\_max:**最大rto

    **刚开始tcp建立连接的时候:**

            1、发送端给接收端发送**syn包**,包含了**seq值**和发送端的时间戳**ts1**(存储在**tsv**)。

            2、接收端返回发送端**ack包**,这时**last\_ack**记录了**ack包**的**ack值**,**ack包**包含了**ts1**(存储在tser)。

            3、发送端收到接收端返回的**ack包**后,发送端**初始化m、srtt、mdev、mdev\_max和rto**。这时候发送端的时间戳是**ts2**。

                    **m = ts2 - ts1**

                    **srtt = m**

                    **mdev = srtt/2**

                    **mdev\_max = max(mdevc, tcp\_rto\_min)**

                    **rto = srtt + 4\*(mdev\_max)**

    **tcp建立连接后的通讯:**

            1、当接收端接收到发送端发送的一个包含了**seq值**和发送端的时间戳**ts1**(存储在**tsv**)的包后,如果接收端的**last\_ack**与**seq值**相等,那么把**ts1**存储到**ts\_recent**中。

            2、接收端返回一个包含了**ts1**(存储在**tser**)的**ack包**,而且接收端把**ack包**的**ack值**存储到**last\_ack**。

            3、发送端收到接收端返回的**ack包**后,发送端**修改m、srtt、mdev、mdev\_max和rto**。这时候发送端的时间戳是**ts2**。

                    **m = ts2 - ts1**

                    当**m大于等于srtt - mdev**的时候:**mdev = mdev \* (3/4) + |m - srtt| \* (1/4)**

                    当**m小于srtt - mdev**的时候:**mdev = mdev \* (31/32) + |m - srtt| \* (1/32)**

                    以上两条是为**解决当m远远小于srtt的时候会导致mdev上升**的问题。

                    **mdev\_max = max(mdev\_max, mdev)**

                    **srtt = srtt \* (7/8) + m \* (1/8)**

                    **rto = srtt + 4 \* mdev\_max**        接收端的**last\_ack**和**ts\_recent**的设计目的是为了在**ts\_recent**中存储**最早的一个未经确认的包**所携带的**tsv**。这样子只要接收端返回一个**ack包**,那么**ack包**中的**tser**存储的就是**最早的一个未经确认的包**所携带的**tsv**。这样子发送端收到**ack包**之后的处理就可以解决**发送端发的包与返回的ack包并不一一对应的问题**。

基于RTO的超时重传

    发送端每发一个包都有相应的**计时器**来计时。当发送端在**RTO**时间里,接收到从接收端返回的一个**ack包**,而且这个**ack包**使得的发送端的**发送窗口前移**,那么就计算**新的RTO**。如果一直没有接收到符合要求的**ack包**,当计时器超过**RTO**时间后,**RTO**就等于**y\*RTO**,而且重传丢失超时的包。**y**是2,4,8等指数增长的值,但**y\*RTO**不能超过**tcp\_rto\_max**。

失序报文(out-of-order segment)

    报文的**seq值**大于接收端记录的**last\_ack**的报文,也就是前面有空缺报文,称为**失序报文**。

重复报文(duplicate segment)

   接收端接收到已经接收过的报文。

重复ACK(Duplicate Acknowledgement)

    不能使得发送窗口前移的ACK是**重复ACK**。

选择重传SACK(Selective Acknowledgement)

SACK-Permitted选项:

    只用于**SYN包**的选项,在**建立连接**的时候,告诉[SYN](https://so.youkuaiyun.com/so/search?q=SYN&spm=1001.2101.3001.7020)包的接收端,发送方支持SACK。

SACK块:

    一对4字节序列号,这表示一个连续的数据段,这个数据段已经被接收端接收了。

SACK选项:

    **SACK选项**包含了n个**SACK块**的信息,长度是**8\*n + 2**字节。每个**SACK块**之间都是互相独立的而且不重复包含的。**第一个SACK块**(紧接着选项长度后的SACK块)的数据段必须包含最近一次接收到的报文的序列号范围,之后的**SACK块**从之前的**重复ACK**中的**SACK块**中从时间上由近到远排列。通过包含**SACK选项**的**重复ACK**,可以知道接收端的接收数据的**空缺**。  
    注意,tcp的**头部长度**最长是**60字节**(由tcp头部的以32位字为单位的4位头部长度限制),tcp的**基本tcp头部**为**20字节**,其中n最大为**4**,而且由于**SACK选项**都是与**TSOPT选项**一起用的,所以n最大是**3**。

伪超时(spurious timeout)

    过早判定超时,就是**伪超时**。实际**RTT**显著增长,超过了当前**RTO**的时候,就可能会出现**伪超时**。

伪重传(spurious retransmission)

    没有出现数据丢失,却引发了重传,这样的重传成为**伪重传**。伪重传造成的原因可能是**伪超时**、**失序报文、重复报文**或ACK丢失。

重复SACK(DSACK/Duplicate Selective Acknowledgement)

    基本的**SACK**机制对于接收端接收到**重复报文**怎么处理没有作出规定。**DSACK**为这个状况提供了方案。在接收到**重复报文**的时候,接收端向发送端发送一个包含**SACK选项**的**重复ACK**。第一个**SACK块**称为**DSACK块**,用于向发送端报告**重复报文**。当**ack包**的**ack值**在**重复报文**的左边界的左边,那么紧接着**DSACK块**的**SACK块**必须要包含**DSACK块**,之后的**SACK块**如同基本的**SACK**机制一样。当**ack包**的**ack值**在**重复报文**中或者在**重复报文**右边界的右边,那么**DSACK块**只是包含**重复报文**的重复部分,之后的**SACK块**如同基本的**SACK**机制一样。发送端接收到这个**重复ACK**,就可以知道导致这个**重复ACK**的是不是**伪重传**。

Eifel检测算法

    **Eifel检测算法**利用TSOPT选项来实现机制。当发送端发送一个重传,就记录当时重传的TSOPT选项的TSV,当发送端接收到ACK(发送窗口前进),那么判断这个ACK的TSOPT选项的TSER是否小于之前记录的TSV。如果小于那么这个ACK是原始分组的ACK而不是重传的ACK,所以是一个**伪重传**。

前移RTO恢复(F-RTO)

    当超时重传之后,收到的第一个ACK时,发送端再发送新数据,之后再响应一个ACK。判断两个ACK是不是**重复ACK**,如果都不是,那么这个超时重传是个**伪重传**,否则就是一个**伪重传**。这种判断方法只能检测**伪超时**导致的**伪重传**。这是检测伪重传的标准算法。

Eifel响应算法

    **Eifel检测算法**与**F-RTO**通过检查ACK或原始传输来判定**伪重传**,称为**伪超时**。**DSACK**通过检测伪超时引发的重传所返回的ACK来判定**伪重传**,称为**迟伪超时**。

    重传计时器超时后,会记录两个变量:

            srtt\_prev = srtt + 2(G)        G代表TCP的始终粒度。

            rttvar\_prev = rttvar

    通过上述的**Eifel检测算法**与**F-RTO**检测出**伪超时**,**DSACK**检测出**迟伪超时**。

    **响应操作**。如果是**伪超时**,那么把snd\_nxt修改为snd\_max。如果是**迟伪超时**,那么snd\_nxt不修改。这些情况都要重新设置拥塞控制状态,并且一旦接收到重传计时器超市后发送的报文的ACK,那么如下设置:

    srtt = max(srtt\_prev, m)        m是时间戳样本值。

    rttvar = max(rttvar\_pre, m/2)

    rto = srtt + max(G,4(rttvar))
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值