TCP重传与超时(Linux)

重传次数

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

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

        Linux通过分别设置net.ipv4.tcp_retries1net.ipv4.tcp_retries2来设置R1R2值。

        对于建立连接的SYNSYN_ACK重传次数,Linux通过分别设置net.ipv4.tcp_syn_retriesnet.ipv4.tcp_synack_retries来设置。

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

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

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

        srtt(Smoothed Round-Trip Time):平滑的rtt。

        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_ackseq值相等,那么把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_ackts_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包的接收端,发送方支持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))

本文章主要参考《TCP/IP详解 卷一:协议》,本人初学,如果有不同意见欢迎留言。

你可能感兴趣的:(tcp/ip,网络,服务器)