Linux下Tcp保活时间默认多少,TCP中的几种超时和定时器

66b52468c121889b900d4956032f1009.png

8种机械键盘轴体对比

本人程序员,要买一个写代码的键盘,请问红轴和茶轴怎么选?

最近重新翻阅了一下Stevens的《TCP/IP详解》,发现不少知识点之前没有理解透彻,或者过了太久已经没有印象了,因此决定花一些时间来整理和记录下来。

超时重传

在TCP中重传可能发生在2种情况下:快速重传和超时重传。超时重传指的是,当发送到对方的报文段在一定超时时间之内,仍没有收到对方的Ack,则重新发送该报文段。

那么问题来了,超时时间是怎么决定的?如果超时时间太长,报文丢失之后很久才重发,效率和吞吐率太低;时间太短,可能某些报文只是延迟到达,并没有丢失,重传又会增加网络负载,可能造成网络拥塞。因此,在不同的网络环境下,甚至在相同网络的不同时间段下,均需要动态地计算超时时间。

通过RTT(Round Trip Time)可以大致决定,在多长时间之内没有收到Ack,则认为该报文丢失,并重传该报文。然而,网络环境随时在变化,我们没有办法准确的确定一个报文的RTT,只能通过多次采样来估算。

RTT的测量和估算

为了尽量准确地估算下一次报文的RTT,TCP需要对已经发送出去报文的RTT进行采样。对于每个连接,在发送数据时,保证全局有一个定时器正在运行(如果发送数据时已经有定时器在运行,则不对该报文进行计时)。

原始算法

最初的TCP规范[RFC0793]使用如下公式估算RTT:SRTT = α(SRTT) + (1 − α) M

SRTT(Smoothed RTT estimator)指平滑后的RTT估算值,α为平滑因子,推荐值为0.9,M为实际测量的RTT值。该算法预测的RTT值90%来自于前一个RTT,10%来自新的测量值。重传超时RTO(Retransmission Timeout)的值设置为RTO = min(ubound, max(lbound, β* SRTT))

ubound和lbound分别RTO的上限和下限,β的推荐值为2。

Jacobson/Karels算法

上述算法的缺点在于,在网络环境突然发生较大变化时,该算法无法跟上这种变化,及时进行相应的调整,因为估算的RTO值只有10%来自于新的测量值。例如,某个中间路由器发生故障导致吞吐率降低,该算法还是会在相对短的时间内重传,继续增加网络负载,是一种雪上加霜的行为。

因此,有人提出一种新的算法,除了计算平滑的RTT值之外,还要计算RTT的变化幅度,RTO根据这两个值来进行确定。这就是Jacobson/Karels算法[RFC6298],该算法具体如下:SRTT = (1 - g)(SRTT) + (g)M

RTTval = (1 - h)(RTTval) + (h)( | M - SRTT | )

RTO = SRTT+ 4(RTTval)

其中g的推荐值为0.125,h的推荐值为0.25

SRTT的计算方法不变,但是该算法还需要计算RTT的加权移动平均值RTTval,该值是被平滑后的RTT测量值与SRTT之差(取绝对值),类似于方差但是计算方法更简单,用于表示RTT的变化幅度。该算法能够更快地跟上网络环境的变化,并做出相应的调整。

那如果SYN报文超时怎么办?此时还没有能够对RTT进行采样,无法根据上述算法计算得出。因此,RFC6298指出,RTO初始值设置为1s。如果第一个SYN报文超时,以该RTO值进行指数退避的同时,将数据传输阶段的RTO初始值设置为3s。

取得第一个RTT采样值M后,对算法进行如下初始化:SRTT = M

RTTval = M / 2

此后,便根据该值和后续RTT采样值来进行后续的计算。

重传二义性和Karn算法

这样做有一个问题,如下图所示,可能会有两种情况,而我们无法判断到底是哪一种:第一次发送的报文丢失,超时重传后,收到对方的Ack

由于网络原因,第一次发送的报文延迟到达,接收方对延迟到达的Ack进行确认,随后收到重传的报文并丢弃

因此,Karn算法指出,一旦发生重传,则不对该报文的RTT进行采样。但是如果网络突然出现故障,导致所有报文的实际RTT大于当前的RTO,则每个报文都会发生重传,同时,又因为不能对重传的报文进行RTT采样,因此也无法更新RTO,这就陷入了僵局,而对每个报文都重传毫无疑问会很大程度上给网络增加没必要的负载,使得网络情况更差。为了避免这种情况,Karn算法的第二点,就是在发生超时重传的情况下,对RTO进行指数退避(exponential backoff),每次进行重传就将当前RTO翻倍,直到下一次没有重传就收到对方的Ack,才根据测量的RTT和SRTT重新计算RTO。这样做的目的在于,消除重传二义性的同时,根据网络环境的变化及时调整RTO,防止进一步使网络过载。发生重传后,在将RTO进行指数退避的同时,触发拥塞避免算法,将thresh值置为当前拥塞窗口的一半,再将拥塞窗口置为1,重新进行慢启动。

超时重传次数

上面讨论了重传的超时时间,但是如果网络出现故障,或者对端主机崩溃,使得报文始终无法发送到对端,当然不可能无限地重传下去,因此,需由系统指定重传次数上限。在Linux下,这个上限是可以配置的,由/proc/sys/net/ipv4目录下的tcp_retries1, tcp_retries2和tcp_syn_retries三个文档指定。tcp_retries1: 重传该文档指定次数之后,则要求网络层更新路由表。默认值为3

tcp_retries2: 重传该文档指定次数之后,放弃传输,即最大重传次数。默认值为15

tcp_syn_retries: 指定syn报文的重传次数。默认值为5(但是在Ubuntu 14.04下查看该值默认为6)

坚持定时器

说完了超时重传的定时器,我们来看一下TCP的坚持定时器(persist timer)。

我们知道,由于TCP的滑动窗口协议,如果接收方向发送方通告的窗口大小为0(例如当接收方应用进程来不及读取接受缓冲区中的数据,导致接受缓冲区占满),那么发送方就不能继续发送数据。当接收方应用进程读取一部分数据,使得滑动窗口不为0时,接收方会向发送方发送一个Ack,这个Ack不确认任何数据,只是告诉新的窗口大小,因此也被称为窗口更新。

但是,这个Ack报文段中不带任何数据,所以不会有任何超时重传的机制来保证该Ack可靠送达。如果这个Ack丢失了,双方岂不是都陷入了无限的等待?发送方等待接收方的窗口更新,接收方等待发送方的数据。

为了避免这个问题,TCP引入了坚持定时器。当发送方在一定时间内没有收到接收方的窗口更新,坚持定时器超时后,会主动向接收方询问当前窗口,这个过程也叫窗口探测(Window Probes),窗口探测其实就是一个包含0字节或1字节数据的报文段。《TCP/IP详解》中写的是1字节,但是在Ubuntu 14.04下实测为0字节,可能是不同的实现方法。接收方收到这个报文后,会向发送方回复Ack,其中包含当前的窗口大小。这个Ack可能会确认该1字节的数据(如果探测报文包含数据的话),也可能不会,这取决与接收方当前的接收缓冲区占用情况。

坚持定时器的首次超时时间为当前RTO,随后进行指数退避(超时时间存在最大上限,在Ubuntu 14.04下,超时时间最大值为120s),直到接收方通告的窗口大小不为0。

抓包结果如下:

可以看到,在最开始,超时时间以指数退避的方式进行增加,直到该值达到120s之后保持不变。《TCP/IP详解》中说:

发送方不会放弃窗口探测,但是从截图中可以看出,在接收方收到一定次数的窗口探测,而应用进程始终没有读取数据时,会向发送方发送RST报文重置连接。

保活定时器

如果连接处于空闲状态,较长时间内没有进行数据交互,如果连接双方任意一方崩溃或发生故障(如掉电或网线拔出等情况,来不及向对端发送FIN或RST),对方是无法感知到的。如果对方确实已经发生故障,则应该关闭该连接,并回收相应的资源,对于并发连接数较大的服务器进程来说,这一点很重要。TCP使用保活定时器(Keep Alive Timer)来做到这一点。

在默认情况下,TCP的保活定时器超时时间为2小时(在Linux下由/proc/sys/net/ipv4/tcp_keepalive_time文档指定),但是每次接收到来自对端发送过来报文,都会将该定时器复位。保活定时器的探测报文是不带任何数据,其中SYN字段比下一个发送的序列号小1。例如,如果本端下一次要发送的序列号为10(即对端上一次回复的Ack是10),那么这个探测报文的Ack是9。正是由于这个不正确的Ack,使得对端对该报文进行响应(该响应中Ack字段为10),表明它期望接收的是10而不是9。

保活探测报文也有超时时间和重传次数的,Linux下分别由/proc/sys/net/ipv4/目录下的tcp_keepalive_intvl和tcp_keepalive_probes文档指定,默认值分别为75s和9次。如果对方始终没有对该探测报文进行响应,就向对端发送RST报文,同时将该连接重置。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值