我是靠谱客的博主 灵巧洋葱,最近开发中收集的这篇文章主要介绍TCP 应用层 心跳包,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

        TCP/IP协议分为4层,分别为应用层、传输层、网络层、数据链路层,TCP协议在TCP/IP协议族的传输层,它提供一种面向连接的、可靠的字节流服务,服务器和客户端交换数据之前必须先建立一个连接,在此基础之上双方进行通信。但实际中会存在各种问题导致掉线(如有的防火墙会关闭长时间没有数据交换的网络、中间路由器断掉等),对于TCP长连接而言,服务器和客户端在很长一段时间内可能不会进行数据交互,但客户端会随时上传数据,因此该连接必须保持。那么如何检测连接的通断情况呢?本文提供两种思路方法,希望还有其他方法的朋友提出来分享交流。

       1、 TCP机制本身提供了一种方法——keepalive机制,在网络空闲一长段时间后底层发出报文,若网络通畅,会收到对端回复的报文,则说明网络通畅,则继续等待空闲一长段时间再发报文,若未收到对端报文则说明网络对端掉线,则每隔一小段时间发送报文,若几次都没有收到对端的报文,则说明对端彻底掉线,本地应用层recv()函数会返回0,则将该套接字关闭。该机制在TCP/IP协议的传输层实现,可以通过应用层设置keepalive的相关参数,代码如下。该方法适合并发服务器检测网络通畅性问题。

int SetTcpKeepalive(int fd, unsigned int start, 
					unsigned int interval, unsigned 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;     
}   

        2、应用层发送心跳包:每隔一段时间向对端发送一个较小的数据包,通知对方自己在线,并传输一些可能必要的数据(如告诉服务器该数据包为心跳包),并且定时检测对端返回的数据,若连续几次在规定时间内均未收到回复,则判断对端掉线,可以做下一步处理。该方法适合用于客户端处理,在应用层开一个线程发送心跳包,本例中只有发送数据包,未做接收数据处理。数据报文如下:

typedef  char  Data;

typedef enum {
	HEART = 0,   //心跳报文头部
	MSG          //数据报文头部
}Type;

typedef struct datapack{
	Type  type;    //若为心跳报文,buf和len为0
	Data  buf[32];
	int   len;
}DataPack;

处理心跳报文的线程函数如下:


void *HeartBeat(void *argc)
{
	int ret = 0;
	int cunt = 0;
	int i = 0;
	DataPack heart_data;
	
	bzero(&heart_data, sizeof(heart_data));
	heart_data.type = HEART;
	heart_data.len = 0;
	
	printf("start send heartbeat data n");

	cunt = 0;
	while(1){
		ret = send(cli_fd, &heart_data, sizeof(heart_data), 0);
		if(ret < 0){
			cunt ++;
                if(errno == EPIPE){
                        //服务器关闭,发送数据导致管道破裂
                       //处理流程
                }
			if(cunt > 5){
				printf("server is offline n");
				printf("the client is going down n");
				exit(0);
			}
			close(cli_fd);
		}
		delay(3000);
	}
}

     在服务器崩溃以后客户端还调用send()函数会导致管道破裂,该信号的默认处理方式为结束进程, 为了避免进程结束可以调用signal函数忽略掉该信号,如下:

        signal(SIGPIPE, SIG_IGN);

   本文中若有不足的地方请各位看官提出。

最后

以上就是灵巧洋葱为你收集整理的TCP 应用层 心跳包的全部内容,希望文章能够帮你解决TCP 应用层 心跳包所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(67)

评论列表共有 0 条评论

立即
投稿
返回
顶部