linux下socket的心跳机制

在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 保活机制, 但是使用它有几个缺点:

  1. 它不是 TCP 的标准协议, 并且是默认关闭的.

  2. TCP keepalive 机制依赖于操作系统的实现, 默认的 keepalive 心跳时间是 两个小时(可自由更改), 并且对 keepalive 的修改需要系统调用(或者修改系统配置), 灵活性不够.

  3. 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探测。

从而得知连接已失效,客户端程序便有机会及时执行清除工作、提醒用户或重新连接。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值