检测连接的原因
需要有机制来发现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)