Linux socket编程的心跳机制总结

Linux socket编程的心跳机制总结

我写这篇文章的目的是想总结一下心跳机制的使用,因为最近两个项目的TCP通信中都使用了这个方法,感觉用法好诗比较经典的,所以拿出来与大家共享。

什么是心跳机制

心跳机制就是当客户端与服务端建立连接后,每隔几分钟发送一个固定消息给服务端,服务端收到后回复一个固定消息给客户端,如果服务端几分钟内没有收到客户端消息,则视客户端断开。发送方可以是客户端和服务端,看具体需求。

为什么要使用

我们都知道在TCP这种长连接情况下下,有可能有一大段时间是没有数据往来的,即处于空闲状态。理论上说,这个连接是一直保持连接的,但是在实际应用中,如果中间节点出现什么故障是难以预测的。更可怕的是,有的节点会自动把一定时间之内没有数据交互的连接切断。所以,需要我们利用心跳机制,来维持长连接,保活通信。

实现方法

  • 应用层: 由应用程序自己每隔一定时间向客户/服务端发送一个短小的数据包,然后启动一个线程,在线程中不断检测客户端的回应, 如果在一定时间内没有收到客户/服务端的回应,即认为客户/服务端已经掉线,连接不可用。
  • 设置SO_KEEPALIVE套接字选项:在TCP通信中,存在heartbeat机制。其实就是TCP的选项。当服务/客户端,一方开启KeepAlive功能后,就会自动在规定时间内向对方发送心跳包, 而另一方在收到心跳包后就会自动回复,以告诉对方我仍然在线。

注意:因为开启KeepAlive功能需要消耗额外的宽带和流量,所以TCP协议层默认并不默认开启KeepAlive。KeepAlive超时需要7,200,000 MilliSeconds, 即2小时,探测次数为5次。对于很多应用程序来说,空闲时间太长。因此,我们可以手工开启KeepAlive功能并设置合理的KeepAlive参数。

我的实现

这里具体介绍设置SO_KEEPALIVE套接字选项这个方法。

SO_KEEPALIVE的三个参数:

  1. tcp_keepalive_intvl:探测发包间隔为intvl。
  2. tcp_keepalive_idle:连接在idle时间内没有任何数据往来,则进行此TCP层的探测。
  3. tcp_keepalive_cnt:尝试探测的次数。

setsockopt()函数介绍

  1. 用法:设置与某个套接字关联的选 项。选项可能存在于多层协议中,它们总会出现在最上面的套接字层。
  2. 函数原型:
#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实现起来最简单,最方便。如果大家发现有什么问题,也欢迎大家交流。

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 08-11

Linux socket编程的心跳机制总结的相关文章

Linux socket编程 DNS查询IP地址

本来是一次计算机网络的实验,但是还没有完全写好,DNS的响应请求报文的冗余信息太多了,不只有IP地址.所以这次的实验主要就是解析DNS报文.同时也需要正确的填充请求报文.如果代码有什么bug,欢迎指正啊.代码排版有点乱... 本文有以下内容 DNS报文的填充和解析 利用socket API传输信息 一.填充DNS请求报文 随便百度一下,就可以知道DNS报文的格式.所以这里只介绍如何填充DNS报文. 首先是填充报文首部: ? 1 2 3 4 5 6 7 8 9 /* 填充首部的格式大致相同,下面的

Linux Socket编程-(转自吴秦(Tyler))

"一切皆Socket!" 话虽些许夸张,但是事实也是,现在的网络编程几乎都是用的socket. --有感于实际编程和开源项目研究. 我们深谙信息交流的价值,那网络中进程之间如何通信,如我们每天打开浏览器浏览网页时,浏览器的进程怎么与web服务器通信的?当你用QQ聊天时,QQ进程怎么与服务器或你好友所在的QQ进程通信?这些都得靠socket?那什么是socket?socket的类型有哪些?还有socket的基本函数,这些都是本文想介绍的.本文的主要内容如下: 1.网络中进程之间如何通信?

Linux Socket编程(不限Linux)

话虽些许夸张,但是事实也是,现在的网络编程几乎都是用的socket. ——有感于实际编程和开源项目研究. 我们深谙信息交流的价值,那网络中进程之间如何通信,如我们每天打开浏览器浏览网页时,浏览器的进程怎么与web服务器通信的?当你用QQ聊天时,QQ进程怎么与服务器或你好友所在的QQ进程通信?这些都得靠socket?那什么是socket?socket的类型有哪些?还有socket的基本函数,这些都是本文想介绍的.本文的主要内容如下: 1.网络中进程之间如何通信? 2.Socket是什么? 3.so

Windows Socket和Linux Socket编程的区别 ZZ

socket相关程序从Windows移植到Linux下需要注意的: 1)头文件 Windows下winsock.h/winsock2.h Linux下sys/socket.h 错误处理:errno.h 2)初始化 Windows下需要用WSAStartup Linux下不需要 3)关闭socket Windows下closesocket(...) Linux下close(...) 4)类型 Windows下SOCKET Linux下int 如我用到的一些宏: #ifdef WIN32 typed

linux socket 编程(C语言)

转自:http://blog.csdn.net/piaojun_pj/article/details/5920888 最近看了一些网络编程的书籍,一直以来总感觉网络编程神秘莫测,其实网络编程入门还是很容易学的,下面这些代码是我在linux下编写的,已经运行过了,编译之后就可以运行了.有不足之处希望大家多多指出,共同学习交流. 套接字是一种进程间的通信的方法,不同于以往介绍的进程间通信方法的是,它并不局限于同一台计算机的资源,例如文件系统空间,共享内存或者消息队列.套接字可以认为是对管道概念的扩展

Linux socket编程入门(1)-TCP服务端

#include<stdio.h> #include<stdlib.h> #include<string.h> #include<errno.h> #include<sys/types.h> #include<sys/socket.h> #include<netinet/in.h> #define DEFAULT_PORT 8000 #define MAXLINE 4096 int main(int argc, char

Linux Socket编程注意事项

Socket API 是网络应用程序开发中实际应用的标准 API.虽然该 API 简单.可是开发新手可能会经历一些常见的问题.本文识别一些最常见的隐患并向您显示怎样避免它们. 隐患 1.忽略返回状态 第一个隐患非常明显,但它是开发新手最easy犯的一个错误. 假设您忽略函数的返回状态,当它们失败或部分成功的时候,您或许会迷失. 反过来.这可能传播错误.使定位问题的源头变得困难. 捕获并检查每个返回状态.而不是忽略它们.考虑清单 1 显示的样例,一个套接字 send 函数. 清单 1. 忽略 AP

linux socket编程示例

#include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <signal.h> #include <unistd.h> #include <stdlib.h> #include <assert.h> #include <stdio.h> #include <string.h> static bool

TCP IO复用 select并发服务端 Linux socket编程入门(3)

在写这段代码的时候,发现很多地方容易弄错.select有可能会出错,返回-1. 比如 int FD_ISSET(int fd,fd_set *fdset); void FD_CLR(int fd,fd_set *fdset); void FD_SET(int fd,fd_set *fdset); void FD_ZERO(int fd,fd_set *fdset); 这里的几个宏都是传入指针,而不是值传递. select函数声明如下: int select(int maxfdp1,fd_set