好记性不如铅笔头

编程

TCP Keepalive报文简单概念笔记

本文转自【 http://www.blogjava.net/yongboy/archive/2015/04/14/424413.html 】,有大量删改。

KeepAlive介绍

TCP是无感知的虚拟连接,中间断开两端不会立刻得到通知一般在使用长连接的环境下,需要心跳保活机制可以勉强感知其存活。业务层面有心跳机制,TCP协议也提供了心跳保活机制。协议基于RFC1122#TCP Keep-Alives

TCP Keepalive虽不是标准规范,但操作系统一旦实现,默认情况下须为关闭,可以被上层应用开启和关闭。
TCP Keepalive必须在没有任何数据(包括ACK包)接收之后的周期内才会被发送,允许配置,默认值不能够小于2个小时。
不包含数据的ACK段在被TCP发送时没有可靠性保证,意即一旦发送,不确保一定发送成功,系统实现不能对任何特定探针包作死连接对待。
规范建议keepalive保活包不应该包含数据,但也可以包含1个无意义的字节,比如0x0。SEG.SEQ = SND.NXT-1,即TCP保活探测报文序列号将前一个TCP报文序列号减1。SND.NXT = RCV.NXT,即下一次发送正常报文序号等于ACK序列号;总之保活报文不在窗口控制范围内
TCP Keepalive应该在服务器端启用,方便服务器端清理无效TCP连接,客户端不做任何改动;若单独在客户端启用,若客户端异常崩溃或出现连接故障,存在服务器无限期的为已打开的但已失效的文件描述符消耗资源的严重问题。但在特殊的NFS文件系统环境下,需要客户端和服务器端都要启用Tcp Keepalive机制。

有一张图,可以很容易说明,但请仔细观察Tcp Keepalive部分:

Tcp keepalive 如何使用

在Linux服务器下,keepalive由如下几个参数设置:
tcp_keepalive_time:在TCP保活打开的情况下,最后一次数据交换到TCP发送第一个保活探测包的间隔,即允许的持续空闲时长,或者说每次正常发送心跳的周期,默认值为7200s(2h)。
tcp_keepalive_probes:在tcp_keepalive_time之后,没有接收到对方确认,继续发送保活探测包次数,默认值为9(次)
tcp_keepalive_intvl:在tcp_keepalive_time之后,没有接收到对方确认,继续发送保活探测包的发送频率,默认值为75s。

发送频率tcp_keepalive_intvl乘以发送次数tcp_keepalive_probes,就得到了从开始探测到放弃探测确定连接断开的时间。

启用TCP Keepalive的应用程序,一般可以捕获到下面几种类型错误:
ETIMEOUT 超时错误:在发送一个探测保护包经过(tcp_keepalive_time + tcp_keepalive_intvl * tcp_keepalive_probes)时间后仍然没有接收到ACK确认情况下触发的异常,套接字被关闭
EHOSTUNREACH host unreachable(主机不可达)错误:这个应该是ICMP汇报给上层应用的。
链接被重置:终端可能崩溃死机重启之后,接收到来自服务器的报文,然物是人非,前朝往事,只能报以无奈重置宣告之。

Leave a Reply

12 − 10 =

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据