我写这篇文章的目的是想总结一下心跳机制的使用,因为最近两个项目的TCP通信中都使用了这个方法,感觉用法好诗比较经典的,所以拿出来与大家共享。
心跳机制就是当客户端与服务端建立连接后,每隔几分钟发送一个固定消息给服务端,服务端收到后回复一个固定消息给客户端,如果服务端几分钟内没有收到客户端消息,则视客户端断开。发送方可以是客户端和服务端,看具体需求。
我们都知道在TCP这种长连接情况下下,有可能有一大段时间是没有数据往来的,即处于空闲状态。理论上说,这个连接是一直保持连接的,但是在实际应用中,如果中间节点出现什么故障是难以预测的。更可怕的是,有的节点会自动把一定时间之内没有数据交互的连接切断。所以,需要我们利用心跳机制,来维持长连接,保活通信。
注意:因为开启KeepAlive功能需要消耗额外的宽带和流量,所以TCP协议层默认并不默认开启KeepAlive。KeepAlive超时需要7,200,000 MilliSeconds, 即2小时,探测次数为5次。对于很多应用程序来说,空闲时间太长。因此,我们可以手工开启KeepAlive功能并设置合理的KeepAlive参数。
这里具体介绍设置SO_KEEPALIVE套接字选项这个方法。
#include <sys/types.h>
#include <sys/socket.h>
int setsockopt(int sock, int level, int optname, const void *optval, socklen_t optlen);
参数:
sock:将要被设置或者获取选项的套接字。
level:选项所在的协议层。
optname:需要访问的选项名。
optval:对于getsockopt(),指向返回选项值的缓冲。对于setsockopt(),指向包含新选项值的缓冲。
optlen:对于getsockopt(),作为入口参数时,选项值的最大长度。作为出口参数时,选项值的实际长度。对于setsockopt(),现选项的长度。
返回说明:
成功执行时,返回0。失败返回-1,errno被设为以下的某个值
EBADF:sock不是有效的文件描述词
EFAULT:optval指向的内存并非有效的进程空间
EINVAL:在调用setsockopt()时,optlen无效
ENOPROTOOPT:指定的协议层不能识别选项
ENOTSOCK:sock描述的不是套接字
int heartbeat(int fd)
{
int alive,error,idle,cnt,intv;
/*
* open keepalive on fd
*/
Restart:
alive = 1;//set keepalive open
ret=setsockopt(fd,SOL_SOCKET,SO_KEEPALIVE,&alive,sizeof(alive));
if(ret < 0)
{
DEBUG("set socket option error.\n");
goto Restart;
}
/*
* 60S without data,send heartbeat package
*/
idle = 60;
ret = setsockopt(fd,SOL_TCP,TCP_KEEPIDLE,&idle,sizeof(idle));
if(ret < 0)
{
DEBUG("set keepalive idle error.\n");
return -1;
}
/*
* without any respond,3m later resend package
*/
intv = 180;
ret = setsockopt(fd,SOL_TCP,TCP_KEEPINTVL,&intv,sizeof(intv));
if(ret < 0)
{
DEBUG("set keepalive intv error.\n");
return -2;
}
/*
* send 5 times,without any response,mean connect lose
*/
cnt = 5;
ret = setsockopt(fd,SOL_TCP,TCP_KEEPCNT,&cnt,sizeof(cnt));
if(ret < 0)
{
DEBUG("set keepalive cnt error.\n");
return -3;
}
}
注意:代码中的DEBUG为我自己定义的调试宏,具体可以参见https://github.com/AnSwErYWJ/DogFood/blob/master/debug.c。或者http://blog.csdn.net/u011192270/article/details/47618225
当然,还是有很多方法去实现心跳机制的,比如利用select实现的超时控制,或者利用守护进程或线程的单独检测。不过我个人认为设置SO_KEEPALIVE实现起来最简单,最方便。如果大家发现有什么问题,也欢迎大家交流。
版权声明:本文为博主原创文章,未经博主允许不得转载。
原文地址:http://blog.csdn.net/u011192270/article/details/47621771