浅谈TCP keepalive

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

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

    默认情况下,TCP的keepalive功能是关闭的,所以在前面的例子中server端的CLOSE_WAIT连接会一直保持,可以通过下面的方式打开该功能:

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

系统默认的keepalive参数可以通过/proc或sysctl获取:

182423_7YXw_2310891.png

如果希望将keepalive机制引入程序中,并修改相关参数,可以通过两种方法:

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

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

由于我们不想改动全局配置,因此选择第二种方法,修改套接字选项:

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端的修改。

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

183450_avh1_2310891.png

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

184058_qXlS_2310891.png

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

184715_W6Ya_2310891.png

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

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



转载于:https://my.oschina.net/u/2310891/blog/375429

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值