浅谈TCP keepalive

    在上一篇文章中曾经提到过,当server端收到来自client的FIN后却一直不关闭链接,TCP链接将进入CLOSE_WAIT状态,并一直维持该状态,实际上这时client端早已退出,这无疑是一种资源的浪费。在实际的生产环境中,因为掉电、系统崩溃、网络异常等缘由,这种状况是颇有可能发生的,因而咱们须要一种方法来进行链接的探测和保活,及时判断出异常状况的发生,释放链接资源。html

    TCP的keepalive机制就是为这项任务而生的,详细的描述见http://www.tldp.org/HOWTO/html_single/TCP-Keepalive-HOWTO/网络

    默认状况下,TCP的keepalive功能是关闭的,因此在前面的例子中server端的CLOSE_WAIT链接会一直保持,能够经过下面的方式打开该功能:code

int keepalive = 1;/*on*/
setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, &keepalive, sizeof(keepalive));

系统默认的keepalive参数能够经过/proc或sysctl获取:server

若是但愿将keepalive机制引入程序中,并修改相关参数,能够经过两种方法:htm

  • 经过/proc或sysctl修改全局配置,也就是上图中的内容;资源

  • 经过套接字选项修改特定于套接字的配置;get

因为咱们不想改动全局配置,所以选择第二种方法,修改套接字选项:class

int keepalive_idle = 120;
setsockopt(sock, SOL_TCP, TCP_KEEPIDLE, &keepalive_idle, sizeof(keepalive_idle));

int keepalive_intvl = 30;
setsockopt(sock, SOL_TCP, TCP_KEEPINTVL, &keepalive_intvl, sizeof(keepalive_intvl));

int keepalive_cnt = 5;
setsockopt(sock, SOL_TCP, TCP_KEEPCNT, &keepalive_cnt, sizeof(keepalive_cnt));

注意:这里咱们但愿在server端增长保活探测机制,因此上述代码都是在server端的修改。
cli

从新运行修改后的程序,并在server端使用netstat观察:配置


能够看到,keepalive的timer开始运行起来了,一段时间后CLOSE_WAIT的链接将被释放:

下面经过实际的抓包看看到底发生了什么?

能够看到,在数据流量结束120s(TCP_KEEPIDLE)后,服务端发送了一个keepalive报文,该报文是一个长度为0的"duplicate-ack",且序列号比上一个ACK少1。

此时,因为client早已退出,所以协议栈会回复一个RST,server端也就此当即退出了,后续的探测也就不会再进行了。

相关文章
相关标签/搜索