TCP keepalive机制分析

TCP keepalive是由TCP协议栈提供的连接存活性检测功能。如果打开这个功能特性,如果一条已建立的TCP连接一段时间没有收到报文,就会开始发送TCP keepalive报文,如果keepalive报文多次没有获得响应,则判定连接的对端已经断开,本地协议栈会将连接关闭。

TCP keepalive一般用于服务器软件中,目的是避免客户端异常断开连接造成服务端大量无效连接残留,消耗过多资源。

TCP标准

虽然TCP keepalive在几乎所有主流协议栈(Windows、Linux、BSD)中都有支持,但它并不是TCP标准的一部分,而是由协议栈实现者提供的扩展实现,在RFC1122《Requirements for Internet Hosts -- Communication Layers》中讨论了keepalive未能成为TCP协议标准的原因,以及实现此功能时必须遵守的基本条件。

TCP协议制定者认为keepalive机制不应该成为TCP标准的一部分,主要原因如下:

(1)可能由于暂时的网络故障破坏可以继续正常工作的连接;

(2)消耗不必要的带宽(如果没人用这个连接,它到底是否有效根本无所谓)

(3)如果网络链路按报文数收费会产生额外的费用

从今天看来上述原因几乎是可以忽略不计的,与大量无效却永远存在的连接造成的存储与计算开销相比,几个额外的keepalive报文的代价可以忽略。但仍然有人认为如果想要发现无效连接,应该由应用层协议来实现这个探测和关闭的功能。笔者认为,从逻辑上说TCP作为可靠传输协议,能够自行发现无效传输连接并汇报错误也是符合协议定位的,从工程角度来说在更底层实现一个通用功能也能减轻上层实现复杂度。

实现规范

由于TCP keepalive没有标准规范,因此不同的协议栈对其实现有一定的差异,RFC1122提出了实现keepalive功能必须满足的基本要求:

(1)keepalive功能必须在连接粒度可开关,并且必须默认关闭

(2)keepalive包只能在一段时间没有收到数据报文后发送,这个时间间隔必须是可配置的,且默认长度不能短于2小时

(3)由于不含载荷的ACK分段是不保证可靠传输的,因此keepalive机制不能通过一次检测没收到回应就判定连接失效

标准的TCP keepalive报文应当将seq置为SND.NXT-1,并不包含任何载荷。但由于部分TCP协议栈实现有问题,不能响应这样的keepalive报文,因此也允许发送的keepalive报文中携带1个字节的无效数据来触发对端回应ACK,一般填0。

linux内核协议栈实现

linux内核协议栈实现了TCP keepalive功能,通过setsockopt(..., SO_KEEPALIVE, ...)接口来打开或关闭。对于keepalive检测时延、检测报文间隔长度、检测报文数量,linux提供了内核和socket两个级别的配置。

内核的配置为:

net.ipv4.tcp_keepalive_time = 7200

net.ipv4.tcp_keepalive_intvl = 75

net.ipv4.tcp_keepalive_probes = 9 

socket的配置为:

setsockopt(..., TCP_KEEPIDLE, ...)

setsockopt(..., TCP_KEEPINTVL, ...)

setsockopt(..., TCP_KEEPCNT, ...)

在4.9内核中,keepalive功能在tcp_keepalive_timer函数中实现。通过tcp_write_wakeup函数发送keepalive检测报文,如果多次没有收到回应,调用tcp_send_active_reset发送一个RST报文并产生一个ETIMEDOUT错误。最后发送检测报文的函数是tcp_xmit_probe_skb,可以看到其中将报文seq设置为snd_una - 1,且不包含载荷。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值