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, '