• TCP keepalive的机理及使用


    TCP 是面向连接的 , 在实际应用中通常都需要检测对端是否还处于连接中。如果已断开连接,主要分为以下几种情况:

    1.连接的对端正常关闭,即使用 closesocket 关闭连接。

    2.连接的对端非正常关闭,包括对端异常关闭,网络断开等情况。

    对于第一种情况,很好判断,但是对于第二种情况,可能会要麻烦一些。在网上找到了一些文章,大致有以下两种解决方法:

      自己编写心跳包程序

    简单的说也就是在自己的程序中加入一条线程,定时向对端发送数据包,查看是否有 ACK ,如果有则连接正常,没有的话则连接断开。

      使用 TCP 的 keepalive 机制

    这个需要在 WinSock 编程时对当前 SOCKET 进行相应设置即可,比较方便。

    为了方便起见,我这里采用 keepalive 机制,下面我就以 WinSock 上我实验得到的结果来大致讲一下其机理和使用方法。

    首先说一下 keepalive 来判断异常断开的原理,其实 keepalive 的原理就是 TCP 内嵌的一个心跳包。

    以服务器端为例,如果当前 server 端检测到超过一定时间(默认是 7,200,000 milliseconds ,也就是 2 个小时)没有数据传输,那么会 向client 端发送一个 keep-alive packet (该 keep-alive packet 就是 ACK 和当前 TCP 序列号减一的组合),此时 client 端应该为以下三种情况之一:

    1. client 端仍然存在,网络连接状况良好。此时 client 端会返回一个 ACK 。 server 端接收到 ACK 后重置计时器,在2 小时后再发送探测。如果 2 小时内连接上有数据传输,那么在该时间基础上向后推延 2 个小时。

    2. 客户端异常关闭,或是网络断开。在这两种情况下, client 端都不会响应。服务器没有收到对其发出探测的响应,并且在一定时间(系统默认为 1000 ms )后重复发送 keep-alive packet ,并且重复发送一定次数( 2000 XP 2003 系统默认为 5 次 , Vista 后的系统默认为 10 次)。

    3. 客户端曾经崩溃,但已经重启。这种情况下,服务器将会收到对其存活探测的响应,但该响应是一个复位,从而引起服务器对连接的终止。

    测试代码如下:

    #ifdef WIN32
    //#include <WS2tcpip.h>
    #include <mstcpip.h>
    #else
    #include <netinet/in.h>
    #include <netinet/tcp.h>
    #include <sys/types.h>
    #include <sys/socket.h>
    #include <arpa/inet.h>
    #endif
    void WanLanTcpClient::setKeepalive(int sock, int keepAlive, int keepInterval, int keepCount, int keepIdle)
    {
    #ifdef WIN32
        BOOL bKeepAlive = TRUE;
        int nRet = setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE,
                              (char*)&bKeepAlive, sizeof(bKeepAlive));
        if (nRet == SOCKET_ERROR)
        {
            ERROR_LOG("setsockopt failed: %d", WSAGetLastError());
            return;
        }
        // set KeepAlive parameter
        tcp_keepalive alive_in;
        tcp_keepalive alive_out;
        alive_in.keepalivetime    = keepAlive;  //3000ms
        alive_in.keepaliveinterval  = keepInterval; //300ms
        alive_in.onoff                       = TRUE;
        unsigned long ulBytesReturn = 0;
        nRet = WSAIoctl(sock, SIO_KEEPALIVE_VALS, &alive_in, sizeof(alive_in),
                        &alive_out, sizeof(alive_out), &ulBytesReturn, NULL, NULL);
        if (nRet == SOCKET_ERROR)
        {
            ERROR_LOG("WSAIoctl failed: %d/n", WSAGetLastError());
            return;
        }
    #else
    
        //keepAlive = 1;    //开启keepalive属性. 缺省值: 0(关闭)
        keepIdle = 3;       //如果在1秒内没有任何数据交互,则进行探测. 缺省值:7200(s)
        keepInterval = 1;   //探测时发探测包的时间间隔为1秒. 缺省值:75(s)
        keepCount = 3;      //探测重试的次数. 全部超时则认定连接失效..缺省值:9(次)
        setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, (void*)&keepAlive, sizeof(keepAlive));
        setsockopt(sock, IPPROTO_TCP, TCP_KEEPALIVE, (void*)&keepIdle, sizeof(keepIdle));
        setsockopt(sock, IPPROTO_TCP, TCP_KEEPINTVL, (void*)&keepInterval, sizeof(keepInterval));
        setsockopt(sock, IPPROTO_TCP, TCP_KEEPCNT, (void*)&keepCount, sizeof(keepCount));
    
    #endif
    }
  • 相关阅读:
    预处理01 零基础入门学习C语言50
    内中断01 零基础入门学习汇编语言60
    预处理03 零基础入门学习C语言52
    预处理02 零基础入门学习C语言51
    对《移动互联网白皮书(2013年)》的几个解读
    Windows Azure Mobile Services增加了对 Android的支持并扩展其适用范围至东亚地区
    中国将自主研发操作系统对抗谷歌
    Windows Azure2.5天免费深度技术训练营——面向软件工程师和架构师
    Windows Azure Store:扩大服务市场
    use Visual studio2012 developing kernel driver monitor thread creation on Windows8
  • 原文地址:https://www.cnblogs.com/amwuau/p/8204681.html
Copyright © 2020-2023  润新知