Tcp(keepalive)保活机制

转载:http://www.forlinux.cn/read.php?tid=22&fid=10

Tcp(keepalive)保活机制

最近用树莓派做TCP通讯,client端跟server端通讯,因为这里server是不固定的,所以也就没有固定的心跳支持,这样导致对于一些网络异常状态的检测很不方便,因为是新手所以当时对于keepalive保活机制并不清楚,所以一直纠结,主要还是心里抵触新东西,其实我也知道有这个东西,但是因为没有接触过担心不能一会半会就搞定它,弄起来反而会自己带来一些麻烦,其实在这里我的批评一下自己,本来就是基础不好,还有抵触心理接触新的东西,其实就是在慢慢扼杀自己,如果就这样下去估计我也就走到头了…….哈哈既然我已经认识到了还是要努力改善一下的,

我原本的认知是断网断电后, tcp是死连接, 客户端和服务端是无法感知的,应该借助心跳机制来处理这种问题,这也是我当时因为没有心跳机制感觉烦躁的原因。

后来在网上查了一些资源,可能我目前的状况只能硬着脸皮弄keepalive了,事事总还会有一些意想不到得地方的,其实如果只是单纯的拿keepalive来进行应用的话是很简单,只要配置以下参数就可以了,如果要弄清楚原理可能还要花一大把时间吧,这里就简单说一下具体使用的实现,因为我没不明白吗,就这样吧

心跳就是发送定义好的探测性的数据包,原理上还是很容易理解,在这里我也不多解释,
因为服务端的心跳机制和客户端的心跳机制是一致的, 而且彼此独立。 服务端的心跳只能用来检测服务端的死连接, 客户端的心跳只能检测客户端的死连接,为了简便起见, 我们只在客户端启用心跳机制, 然后让客户端去检测一下死连接。

看一下实际实现代码:

#include 
#include 
#include 
#include 
#include 
#include 
#include   
#include 

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


int main (int argc, char* argv[]) {
    if (argc < 3)
    {
        printf ("用法:%s  <端口号>\n",argv[0]);
        return 0;
    }
    printf ("客户机:创建套接字...\n");
    int sockfd = socket (AF_INET, SOCK_STREAM,0);
    if (sockfd == -1)
    {
        perror ("socket");
        return -1;
    }
    printf ("客户机:准备地址并连接...\n");
    set_tcp_keepAlive(sockfd,2,2,2);
    struct sockaddr_in addr;
    addr.sin_family = AF_INET;
    addr.sin_port = htons (atoi (argv[2]));
    addr.sin_addr.s_addr = inet_addr (argv[1]);
    if (connect (sockfd,(struct sockaddr*)&addr,sizeof (addr)) == -1) 
    {
        perror ("connect");
        return -1;
    }
    printf ("客户机:收发数据...\n");
    for (;;) 
    {
        printf ("> ");
        char buf[1024];
        gets (buf);
        if (send (sockfd, buf,strlen (buf) + 1, 0) == -1) 
        {
            perror ("send");
            return -1;
        }
        memset (buf, 0, sizeof (buf));
        ssize_t rb = recv (sockfd, buf,sizeof (buf), 0);
        if (rb == -1)
        {
            perror ("recv");
            return -1;
        }
        if (rb == 0) 
        {
            printf ("客户机:服务器已宕机!\n");
            break;
        }
        printf ("< %s\n", buf);
    }
    printf ("客户机:关闭套接字...\n");
    close (sockfd);
    return 0;
}

你可能感兴趣的:(网络编程)