linux tcp 默认参数,linux – TCP保持活动参数不被尊重

粗略地说,它应该如何工作是每隔tcp_keepalive_time秒发送一个keepalive消息.如果未收到ACK,则它将探测每个tcp_keepalive_intvl秒.如果在tcp_keepalive_probes之后未收到ACK,则连接将中止.因此,连接最多会中止

tcp_keepalive_time + tcp_keepalive_probes * tcp_keepalive_intvl

没有回应的秒.请参见this内核文档.

我们可以使用netcat keepalive轻松观看这项工作,这是一个允许我们设置tcp keepalive参数的netcat版本(sysctl keepalive参数是默认参数,但它们可以在tcp_sock结构中基于每个套接字覆盖).

首先启动一个侦听端口8888的服务器,其中keepalive_timer设置为5秒,keepalive_intval设置为1秒,keepalive_probes设置为4.

$./nckl-linux -K -O 5 -I 1 -P 4 -l 8888 >/dev/null &

接下来,让我们使用iptables为发送到服务器的ACK数据包引入丢失:

$sudo iptables -A OUTPUT -p tcp --dport 8888 \n > --tcp-flags SYN,ACK,RST,FIN ACK \n > -m statistic --mode random --probability 0.5 \n > -j DROP

这将导致发送到TCP端口8888的数据包仅将ACK标志设置为以0.5的概率丢弃.

现在让我们连接并观察vanilla netcat(它将使用sysctl keepalive值):

$nc localhost 8888

这是捕获:

WcfDJ.png

如您所见,它在收到ACK之后等待5秒钟,然后再发送另一个keepalive消息.如果它在1秒内未收到ACK,则发送另一个探测,如果在4次探测后没有收到ACK,则中止连接.这正是keepalive应该如何工作的.

所以让我们尝试重现你所看到的.让我们删除iptables规则(没有丢失),启动一个新服务器,tcp_keepalive_time设置为1秒,tcp_keepalive_intvl设置为5秒,然后连接客户端.结果如下:

rGWyt.png

有趣的是,我们看到了你所做的相同行为:在第一次ACK之后,它等待1秒钟发送一个keepalive消息,然后每5秒钟.

让我们重新添加iptables规则来引入丢失以查看它在没有得到ACK的情况下实际等待发送另一个探测的时间(在服务器上使用-K -O 1 -I 5 -P 4):

WHhNo.png

同样,它从第一个ACK等待1秒钟以发送保持活动消息,但此后它等待5秒钟是否看到ACK,就像keepalive_time和keepalive_intvl都设置为5一样.

为了理解这种行为,我们需要看一下linux内核的TCP实现.我们先来看看tcp_finish_connect:

if (sock_flag(sk, SOCK_KEEPOPEN))

inet_csk_reset_keepalive_timer(sk, keepalive_time_when(tp));

建立TCP连接后,keepalive定时器有效地设置为tcp_keepalive_time,在我们的例子中为1秒.

接下来,让我们看一下tcp_keepalive_timer中如何处理计时器:

elapsed = keepalive_time_elapsed(tp);

if (elapsed >= keepalive_time_when(tp)) {

/* If the TCP_USER_TIMEOUT option is enabled, use that

* to determine when to timeout instead.

*/

if ((icsk->icsk_user_timeout != 0 &&

elapsed >= icsk->icsk_user_timeout &&

icsk->icsk_probes_out > 0) ||

(icsk->icsk_user_timeout == 0 &&

icsk->icsk_probes_out >= keepalive_probes(tp))) {

tcp_send_active_reset(sk, GFP_ATOMIC);

tcp_write_err(sk);

goto out;

}

if (tcp_write_wakeup(sk, LINUX_MIB_TCPKEEPALIVE) <= 0) {

icsk->icsk_probes_out++;

elapsed = keepalive_intvl_when(tp);

} else {

/* If keepalive was lost due to local congestion,

* try harder.

*/

elapsed = TCP_RESOURCE_PROBE_INTERVAL;

}

} else {

/* It is tp->rcv_tstamp + keepalive_time_when(tp) */

elapsed = keepalive_time_when(tp) - elapsed;

}

sk_mem_reclaim(sk);

resched:

inet_csk_reset_keepalive_timer (sk, elapsed);

goto out;

当keepalive_time_when大于keepalive_itvl_时,此代码按预期工作.但是,如果不是,您会看到您观察到的行为.

当初始定时器(建立TCP连接时设置)在1秒后到期时,我们将延长定时器直到经过的时间大于keepalive_time_when.此时我们将发送一个探测器,并将计时器设置为keepalive_intvl_when,即5秒.当此计时器到期时,如果最后1秒没有收到任何信息(keepalive_time_when),我们将发送一个探测器,然后再次将计时器设置为keepalive_intvl_when,并在另外5秒内唤醒,依此类推.

但是,如果我们在计时器到期时收到keepalive_time_内的某些内容,它将使用keepalive_time_when重新安排计时器,因为我们上次收到任何内容后1秒钟.

因此,为了回答你的问题,TCP keepalive的linux实现假设keepalive_intvl小于keepalive_time,但仍然“明智地”工作.

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值