前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >TCP的KeepAlive探测详解

TCP的KeepAlive探测详解

作者头像
glinuxer
发布2019-04-10 14:56:44
5.1K0
发布2019-04-10 14:56:44
举报
文章被收录于专栏:专注网络研发专注网络研发

在写TCP服务程序时,除了要处理SIGPIPE外,还要有客户端连接检测机制,用于及时发现崩溃的客户端连接。一般来说,有两种检测方式:1. 在应用层,由业务程序自己检测;2. 使用TCP的KeepAlive机制。

使用第一种方式,意味着要在应用层自己实现一个ping-pong逻辑和协议,并支持设置空闲时长,重试次数,重试间隔等。这无疑会增加一定的代码量,好处则是可以自己控制逻辑,同时不用学习内核的实现:)

但是如果没有特殊的需求,我更倾向于第二种方式。如非必要,不要引入额外的逻辑。更何况既然TCP本身已经支持KeepAlive,为什么还要自己实现一套,多此一举呢?代码写的越多,越可能引入Bug:D

本文将对TCP的KeepAlive的使用和原理做比较详细的分析。先看如何使用TCP KeepAlive来检测“失联”的TCP连接。完整的测试代码位于:https://github.com/gfreewind/LinuxDetails/blob/master/networks/6.tcp_keepalive_reporter/tcp_keepalive_report.c。

本文只截图几个关键的函数

其中SO_KEEPALIVE用于打开或者关闭KeepAlive功能,TCP_KEEPIDLE用于设置空闲时间——即有多久没有发送报文就进行探测,TCP_KEEPCNT用于设置KeepAlive的尝试次数,TCP_KEEPINTVL用于设置重试KeepAlive的报文间隔。这里容易搞混的是TCP_KEEPIDLE和TCP_KEEPINTVL,前者是需要进行KeepAlive探测的空闲时间,而后者是在某次KeepAlive探测失败,再次重试的间隔时间。对于上面的程序来说,当该TCP连接有5秒没有进行数据传输时,就会发送KeepAlive探测报文。当探测报文失败时,会隔2秒再次发送探测报文,3次探测失败就判断连接失败。

通过测试程序,我们可以使用tcpdump抓包,来分析KeepAlive。

前三个报文是TCP的三次握手,连接成功后,没有任何报文发送。间隔5秒后,发送KeepAlive,即第4个报文。第5个报文为KeepAlive ACK。再间隔5秒后,再次发送KeepAlive探测报文,即第6个报文。

(请忽略报文的黑颜色,因为这个测试是本机发给本机,所以TCP校验和是不正确的——没有真正通过网卡)

为了测试KeepAlive检测报文失败的情况,在连接成功之后,我使用iptables创建一条规则,丢弃发往port 34567端口的数据报文。这时抓包结果如下:

同上,前三个报文完成TCP三次握手,间隔5秒后发送KeepAlive探测报文,但由于没有收到ACK,所以每间隔2秒再次发送KeepAlive,重试3次后,判定连接失败,在11秒时(应该发送第4个KeepAlive时)发送RST给对端,中断连接。

那么当KeepAlive机制判断连接崩溃时,应用层如何得到通知呢?当连接正常关闭时,应用层可以得到可读事件通知,并且进行read操作时,返回结果为0——这也是服务端判断客户端关闭连接的方法。就此推测,KeepAlive机制判断连接崩溃时,其行为应该与正常关闭类似。在测试代码中,分别使用了select和epoll来进行io事件测试,其输出如下:

根据测试,无论是使用select还是epoll,当KeepAlive中止连接时,应用层都可以得到可读事件通知,并且read结果为0。上面的输出,还有一个sock err is 110的结果。这是另外一种判断机制:

当KeepAlive中断连接时,其会设置socket错误,应用层通过getsockopt即SO_ERR可以获得该错误。

通过测试程序,我们只是学到了KeepAlive的使用方法。接下来就要进入内核对KeepAlive一探究竟。

tcp_keepalive_timer为KeepAlive定时器的回调函数。在这个函数中

当探测超时,就会调用tcp_send_active_reset向对端发送RST报文,中止连接,然后调用tcp_write_err。

设置sk->sk_err等于ETIMEOUT,其值就是测试程序打印的110。而sk_error_report指向的是sock_def_error_report。

其会唤醒等待在当前套接字的进程,且其IO事件是POLLERR。

而在使用epoll_ctl添加监听fd时,内核会自动把EPOLLERR和EPOLLHUP加到监听事件中。这就是为什么epoll可以得到通知。

至此,我们已经从实现和使用上,完成了对TCP KeepAlive机制的探索。

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2017-06-26,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 LinuxerPub 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档