网络编程实战 Keep-alive和心跳检测无效连接

本文探讨了网络编程中检测TCP连接有效性的必要性,并详细介绍了TCP Keep-Alive选项的工作原理及默认设置。当Keep-alive无法满足快速检测失效连接的需求时,提出了应用层的Ping-Pong探活机制作为解决方案。最后提到了UDP协议因其无连接特性,无需此类检测机制。
摘要由CSDN通过智能技术生成

检测连接的原因

需要有机制来发现TCP连接是有效的还是无效的。比如客户端突然崩溃,服务器端可能几天内都维护一个无用的TCP连接

TCP Keep-Alive选项

**原理:**定义一个时间段,这个时间段内如果没有任何连接相关的活动,TCP保活机制就会开始作用,每隔一个时间间隔,发送一个数据很少的探测报文,如果连续几个探测报文都没有得到响应,则认为当前的TCP连接已经死亡,系统内核将错误信息通知给上层应用程序。

参数:上述的可定义变量,分别被称为保活时间、保活时间间隔和保活探测次数。在 Linux 系统中,这些变量分别对应 sysctl 变量net.ipv4.tcp_keepalive_time、net.ipv4.tcp_keepalive_intvl、 net.ipv4.tcp_keepalve_probes,默认设置是 7200 秒(2 小时)、75 秒和 9 次探测。

几种情况:
1.对端程序是正常工作的。当 TCP 保活的探测报文发送给对端, 对端会正常响应,这样 TCP 保活时间会被重置

2.对端程序崩溃并重启。当 TCP 保活的探测报文发送给对端后,对端是可以响应的,但由于没有该连接的有效信息,会产生一个 RST 报文,这样很快就会发现 TCP 连接已经被重置。

3.是对端程序崩溃,或对端由于其他原因导致报文不可达。当 TCP 保活的探测报文发送给对端后没有响应,连续几次,达到保活探测次数后,TCP 会报告该 TCP 连接已经死亡。

保活机制方向
●服务端到客户端:可以在客户非正常断联的情况下清除在服务端保留的“脏数据”
●客户端到服务端:可以在服务器无响应的情况下,重新发起连接

缺点
最少要经过2小时11分15秒(2小时+75秒*9)才能发现一个“死亡”连接,时间太长。需要在应用层来寻找更好的解决方案。

应用层探活 Ping-Pong机制

**原理:**模拟TCP Keep-Alive机制。需要保活的一方在保活时间到达后,发起对连接的PING操作,如果服务器端对PING有回应,重新设置保活时间,否则对探测次数进行计数,如果最终探测次数到了预先设定的阈值,认为连接无效。

设计:
●定时器:用select自带的定时器
●消息格式设计:四种

typedef struct {
   
    u_int32_t type;
    char data[1024];
} messageObject;
#define MSG_PING          1	//ping类型
#define MSG_PONG          2	//pong类型
#define MSG_TYPE1        11	//消息类型1
#define MSG_TYPE2        21	//消息类型2

●客户端程序:模拟TCP Keep-Alive机制,在保活时间到达后,探活次数加一,同时向服务器发送PING格式消息,此后以预设的时间间隔不断PING,如果能收到服务器应答,结束保活,重置为0。

#include"../lib/common.h"

typedef struct {
   
    u_int32_t type;
    char data[1024];
} messageObject;

#define MSG_PING          1
#define MSG_PONG          2
#define MSG_TYPE1        11
#define MSG_TYPE2        21

#define    MAXLINE     4096
#define    KEEP_ALIVE_TIME  10          //第一次select时间
#define    KEEP_ALIVE_INTERVAL  3       //发送心跳包select时间
#define    KEEP_ALIVE_PROBETIMES  3     //心跳包发送次数

int main(int argc, char **argv){
   
    if(argc != 2)
        error(1, 0, "usage:tcpclient <TPaddress>");

    int socket_fd = socket(AF_INET, SOCK_STREAM, 0);

    struct sockaddr_in server_addr;
    bzero(&server_addr, sizeof(server_addr));
    server_addr.sin_family = AF_INET;
    server_addr.sin_port = htons(SERV_PORT)
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值