zoukankan      html  css  js  c++  java
  • Windows 下TCP长连接保持连接状态TCP keepalive设置

    TCP长连接建立完成后,我们通常需要检测网络的连接状态,以反馈给客户做响应的处理。通过设置TCP keepalive的属性,打开socket的keepalive属性,并设置发送底层心跳包的时间间隔。TCP/IP五层网络模型,我们调用socket等接口是应用层的函数,TCP keepalive是在底层定时发送心跳报文,服务器端接收到底层的心跳报文直接丢弃,不关心其内容。

    以下是windows下TCP keepalive设置的函数:

    #include <mstcpip.h>
    int CClientCtrl::socket_tcp_alive(int socket)
    {
        int ret = 0;
    
    
        int keep_alive = 1;
    
        ret = setsockopt(socket, SOL_SOCKET, SO_KEEPALIVE, (char*)&keep_alive, sizeof(keep_alive));
    
    
        if (ret == SOCKET_ERROR)
    
        {
    
            printf("setsockopt failed: %d 
    ", WSAGetLastError());
    
            return -1;
    
        }
    
    
        struct tcp_keepalive in_keep_alive = {0};
    
        unsigned long ul_in_len = sizeof(struct tcp_keepalive);
    
        struct tcp_keepalive out_keep_alive = {0};
    
        unsigned long ul_out_len = sizeof(struct tcp_keepalive);
    
        unsigned long ul_bytes_return = 0;
    
    
        in_keep_alive.onoff = 1; /*打开keepalive*/
    
        in_keep_alive.keepaliveinterval = 5000; /*发送keepalive心跳时间间隔-单位为毫秒*/
    
        in_keep_alive.keepalivetime = 1000; /*多长时间没有报文开始发送keepalive心跳包-单位为毫秒*/
    
    
        ret = WSAIoctl(socket, SIO_KEEPALIVE_VALS, (LPVOID)&in_keep_alive, ul_in_len,
    
            (LPVOID)&out_keep_alive, ul_out_len, &ul_bytes_return, NULL, NULL);
    
    
        if (ret == SOCKET_ERROR)
    
        {
    
            printf("WSAIoctl failed: %d 
    ", WSAGetLastError());
    
            return -1;
    
        }
    
    
        return 0;
    }

    以TCP 客户端为例:

    SHORT CClientCtrl::connetServer(LPCTSTR strAddr,USHORT portNum)
    {
        AFX_MANAGE_STATE(AfxGetStaticModuleState());
    
        // TODO: Add your dispatch handler code here
        m_addr = strAddr;
         USES_CONVERSION;
         char *pCharAddr = T2A(m_addr);
        
        WSADATA wsd;
        WSAStartup(MAKEWORD(2, 2), &wsd);
        m_sockClient = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
        SOCKADDR_IN  ClientAddr;
    
        ClientAddr.sin_family = AF_INET;
        ClientAddr.sin_addr.S_un.S_addr = inet_addr(pCharAddr);//
        ClientAddr.sin_port = htons(portNum);//m_port
        int n = 0;
        n = connect(m_sockClient, (struct sockaddr*)&ClientAddr, sizeof(ClientAddr));
        if (n == SOCKET_ERROR) {
            
            return -1;
        }
    
        //set keepAlive  
        n = socket_tcp_alive(m_sockClient);//设置keepalive
        if (n <0 )
        {
            return -1;
        }
        
        CreateThread(NULL, 0, &recvFromServer, (LPVOID)this, 0, NULL);
    
        return 0;
    }
    DWORD WINAPI  recvFromServer(LPVOID lpParameter)
    {
        char RecvBuf[MaxBufSize];
        CClientCtrl* pParent = (CClientCtrl*)lpParameter;
        SOCKET *ClientSocket = &(pParent->m_sockClient);
        int iLength;
        while (true) {
            memset(RecvBuf, '', sizeof(RecvBuf));
            iLength = recv(*ClientSocket, RecvBuf, MaxBufSize, 0);
            if (iLength <=0) //error   
            {
    
                strcpy(RecvBuf,"ERROR");
                ::SendMessage(pParent->m_hWnd,WM_RECVMSG,(WPARAM)RecvBuf,0);
    
                break;
            }
            else
            {
                ::SendMessage(pParent->m_hWnd,WM_RECVMSG,(WPARAM)RecvBuf,0);
    
            }
            
    
    
        }
        return 0;
    }

      recv函数的返回值能反应网络的状态;

       iLength = recv(*ClientSocket, RecvBuf, MaxBufSize, 0);

    如果服务器端正常关闭socket ,那么recv 的返回值iLength 为0;这种情况即使不设置keepAlive 也是可以正常返回的;

    如果出现暴力关闭,比如网线被拔,服务器程序强行关闭,recv 的返回值iLength 为-1; 如果不设置keepAlive 的话,这里是不会有任何反应的。 

    参考文献:http://blog.csdn.net/embedded_sky/article/details/42077321

  • 相关阅读:
    初涉SQL Server性能问题(2/4):列出等待资源的会话
    初涉SQL Server性能问题(1/4):服务器概况
    分享
    React Native 自定义radio 单选or多选
    css之定位
    小小小小小小之新闻案例
    paddingmargin的属性与连写
    css标准流和浮动
    css 伪类
    css元素的显示方式
  • 原文地址:https://www.cnblogs.com/small-lazybee/p/15425091.html
Copyright © 2011-2022 走看看