概述
在TCP的机制里面,本身是存在有心跳包的机制的,也就是TCP的选项:SO_KEEPALIVE。
系统默认是设置的2小时的心跳频率。但是它检查不到机器断电、网线拔出、防火墙这些断线。
而且逻辑层处理断线可能也不是那么好处理。一般,如果只是用于保活还是可以的。
为什么需要心跳机制?
因为网络的不可靠性, 有可能在 TCP 保持长连接的过程中, 由于某些突发情况, 例如网线被拔出, 突然掉电等,会造成服务器和客户端的连接中断. 在这些突发情况下, 如果恰好服务器和客户端之间没有交互的话, 那么它们是不能在短时间内发现对方已经掉线的.
心跳机制即可解决此类问题。
TCP协议的KeepAlive机制
默认KeepAlive状态是不打开的。
需要将setsockopt将SOL_SOCKET.SO_KEEPALIVE设置为1才是打开KeepAlive状态,
并且可以设置三个参数:
tcp_keepalive_time ,tcp_keepalive_probes , tcp_keepalive_intvl,
分别表示:连接闲置多久开始发keepalive的ack包、发几个ack包不回复才当对方已断线、两个ack包之间的间隔。
很多网络设备,尤其是NAT路由器,由于其硬件的限制(例如内存、CPU处理能力),无法保持其上的所有连接,因此在必要的时候,会在连接池中选择一些不活跃的连接踢掉。
典型做法是LRU,把最久没有数据的连接给T掉。
通过使用TCP的KeepAlive机制(修改那个time参数),可以让连接每隔一小段时间就产生一些ack包,以降低被踢掉的风险,当然,这样的代价是额外的网络和CPU负担。
如何实现心跳机制?
两种方式实现心跳机制:
-
使用 TCP 协议层面的 keepalive 机制.
-
在应用层上实现自定义的心跳机制.
虽然在 TCP 协议层面上, 提供了 keepalive 保活机制, 但是使用它有几个缺点:
-
它不是 TCP 的标准协议, 并且是默认关闭的.
-
TCP keepalive 机制依赖于操作系统的实现, 默认的 keepalive 心跳时间是 两个小时(可自由更改), 并且对 keepalive 的修改需要系统调用(或者修改系统配置), 灵活性不够.
-
TCP keepalive 与 TCP 协议绑定, 因此如果需要更换为 UDP 协议时, keepalive 机制就失效了.
使用 TCP 层面的 keepalive 机制比自定义的应用层心跳机制节省流量。
下面为封装好的心跳包函数,是利用协议层的keepalive机制实现的,加入项目中参数设置一下即可
#include <netinet/tcp.h>
//参数解释
//fd:网络连接描述符
//start:首次心跳侦测包发送之间的空闲时间
//interval:两次心跳侦测包之间的间隔时间
//count:探测次数,即将几次探测失败判定为TCP断开
int set_tcp_keepAlive(int fd, int start, int interval, int count)
{
int keepAlive = 1;
if (fd < 0 || start < 0 || interval < 0 || count < 0) return -1; //入口参数检查 ,编程的好习惯。
//启用心跳机制,如果您想关闭,将keepAlive置零即可
if(setsockopt(fd,SOL_SOCKET,SO_KEEPALIVE,(void*)&keepAlive,sizeof(keepAlive)) == -1)
{
perror("setsockopt");
return -1;
}
//启用心跳机制开始到首次心跳侦测包发送之间的空闲时间
if(setsockopt(fd,SOL_TCP,TCP_KEEPIDLE,(void *)&start,sizeof(start)) == -1)
{
perror("setsockopt");
return -1;
}
//两次心跳侦测包之间的间隔时间
if(setsockopt(fd,SOL_TCP,TCP_KEEPINTVL,(void *)&interval,sizeof(interval)) == -1)
{
perror("setsockopt");
return -1;
}
//探测次数,即将几次探测失败判定为TCP断开
if(setsockopt(fd,SOL_TCP,TCP_KEEPCNT,(void *)&count,sizeof(count)) == -1)
{
perror("setsockopt");
return -1;
}
return 0;
}
将想设置的参数传入该函数,设置成功返回0,否则返回-1。设置成功以后,可以将fd交给select去监听可读可写事件,如果select检测到fd可读且read返回错误,一般就能判定该fd对应的TCP连接已经异常断开,调用close函数将fd关闭即可。
TCP连接非正常断开的检测(KeepAlive探测)
此处的”非正常断开”指TCP连接不是以优雅的方式断开,如网线故障等物理链路的原因,还有突然主机断电等原因
有两种方法可以检测:
1.TCP连接双方定时发握手消息
2.利用TCP协议栈中的KeepAlive探测
第二种方法简单可靠,只需对TCP连接两个Socket设定KeepAlive探测。
从而得知连接已失效,客户端程序便有机会及时执行清除工作、提醒用户或重新连接。
最后
以上就是不安乌龟为你收集整理的linux下socket的心跳机制的全部内容,希望文章能够帮你解决linux下socket的心跳机制所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复