心跳包

来源:互联网 发布:java开发工程师做什么 编辑:程序博客网 时间:2024/04/28 19:16
Socket编程中:心跳包的实现机制
       心跳包之所以叫心跳包是因为:它像心跳一样每隔固定时间发一次,以此来告诉服务器,这个客户端还活着。事实上这是为了保持长连接,至于这个包的内容,是没有什么特别规定的,不过一般都是很小的包,或者只包含包头的一个空包。
       在TCP/IP的机制里面,本身是存在有心跳包的机制的,也就是TCP的选项:SO_KEEPALIVE。系统默认是设置的2小时的心跳频率。但是它检查不到机器断电、网线拔出、防火墙这些断线。而且逻辑层处理断线可能也不是那么好处理。一般,如果只是用于保活还是可以的。
    心跳包一般来说都是在逻辑层发送空的echo包来实现的。下一个定时器,在一定时间间隔下发送一个空包给客户端,然后客户端反馈一个同样的空包回来,服务器如果在一定时间内收不到客户端发送过来的反馈包,那就只有认定说掉线了。
    其实,要判定掉线,只需要send或者recv一下,如果结果为零,则为掉线。但是,在长连接下,有可能很长一段时间都没有数据往来。理论上说,这个连接是一直保持连接的,但是实际情况中,如果中间节点出现什么故障是难以知道的。更要命的是,有的节点(防火墙)会自动把一定时间之内没有数据交互的连接给断掉。在这个时候,就需要我们的心跳包了,用于维持长连接,保活。

    在获知了断线之后,服务器逻辑可能需要做一些事情,比如断线后的数据清理呀,重新连接呀……当然,这个自然是要由逻辑层根据需求去做了。总的来说,心跳包主要也就是用于长连接的保活和断线处理。一般的应用下,判定时间在30-40秒比较不错。如果实在要求高,那就在6-9秒.



 

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <signal.h>

int client_fd;
static int flag = 0;
struct sockaddr_in peer_addr;
int addrlen = sizeof(struct sockaddr_in);

void handler_function(int signum)
{
    int i = 0;

    if(flag == 0)
    {
        for(i = 0;i < 3;i ++)
        {
            sendto(client_fd,NULL,0,0,(struct sockaddr *)&peer_addr,addrlen);
            usleep(500);
        }
        
        alarm(10);
        flag = 1;
    
    }else{
        
        printf("The server is closed.\n");
        kill(getppid(),SIGKILL);
        exit(EXIT_SUCCESS);
    }

    return;
}

int main(int argc,char *argv[])
{
    char buf[100];

    signal(SIGALRM,handler_function);

    if(argc < 3)
    {
        fprintf(stderr,"usage : %s ip port.\n",argv[0]);
        exit(EXIT_FAILURE);
    }

    if((client_fd = socket(AF_INET,SOCK_DGRAM,0)) < 0)
    {
        perror("Fail to socket");
        exit(EXIT_FAILURE);
    }

    bzero(&peer_addr,sizeof(peer_addr));
    peer_addr.sin_family = AF_INET;
    peer_addr.sin_port = htons(atoi(argv[2]));
    peer_addr.sin_addr.s_addr = inet_addr(argv[1]);

    alarm(10);

    while(1)
    {
        sleep(1);
        sendto(client_fd,NULL,0,0,(struct sockaddr *)&peer_addr,addrlen);
        recvfrom(client_fd,NULL,0,0,NULL,NULL);
        alarm(10);
        if(flag == 1)
            flag = 0;
    }

    exit(EXIT_FAILURE);
}


原创粉丝点击