/* VC下SOCKET通信,设置非阻塞模式,添加心跳检查 */
#include
#pragma comment(lib, "ws2_32.lib")
/* mstcpip.h */
struct tcp_keepalive
{
u_long onoff;
u_long keepalivetime;
u_long keepaliveinterval;
};
typedef struct tcp_keepalive TCP_KEEPALIVE;
// New WSAIoctl Options
#define SIO_RCVALL _WSAIOW(IOC_VENDOR,1)
#define SIO_RCVALL_MCAST _WSAIOW(IOC_VENDOR,2)
#define SIO_RCVALL_IGMPMCAST _WSAIOW(IOC_VENDOR,3)
#define SIO_KEEPALIVE_VALS _WSAIOW(IOC_VENDOR,4)
#define SIO_ABSORB_RTRALERT _WSAIOW(IOC_VENDOR,5)
#define SIO_UCAST_IF _WSAIOW(IOC_VENDOR,6)
#define SIO_LIMIT_BROADCASTS _WSAIOW(IOC_VENDOR,7)
#define SIO_INDEX_BIND _WSAIOW(IOC_VENDOR,8)
#define SIO_INDEX_MCASTIF _WSAIOW(IOC_VENDOR,9)
#define SIO_INDEX_ADD_MCAST _WSAIOW(IOC_VENDOR,10)
#define SIO_INDEX_DEL_MCAST _WSAIOW(IOC_VENDOR,11)
/* mstcpip.h end */
#define WM_TCP_RECV_DATA WM_USER+201 // 网络接受数据
#define WM_TCP_CONNECT WM_USER+202 // 网络连接
#define WM_TCP_DISCONNECT WM_USER+203 // 网络断开
#define RECV_BUFFER_SIZE 1024
// 设置socket心跳检测有效
void SetKeepAlive(SOCKET sockfd)
{
/* set socket keepalive mode */
int alive = 1;
setsockopt(sockfd, SOL_SOCKET, SO_KEEPALIVE, (char *)&alive, sizeof(alive));
/* set keepalive param */
TCP_KEEPALIVE inKeepAlive = {0};
unsigned long ulInLen = sizeof(TCP_KEEPALIVE);
TCP_KEEPALIVE outKeepAlive = {0};
unsigned long ulOutLen = sizeof(TCP_KEEPALIVE);
unsigned long ulBytesReturn = 0;
inKeepAlive.onoff = 1;
inKeepAlive.keepaliveinterval = 500; //单位为毫秒
inKeepAlive.keepalivetime = 100; //单位为毫秒
WSAIoctl(sockfd, SIO_KEEPALIVE_VALS, (LPVOID)&inKeepAlive, ulInLen, (LPVOID)&outKeepAlive, ulOutLen, &ulBytesReturn, NULL, NULL);
// 设置socket为非阻塞
u_long imode = 1; // 0为阻塞,非0为非阻塞
ioctlsocket(sockfd, FIONBIO, &imode);
}
// 心跳检查函数
UINT TcpKeepAliveThreadFunc(LPVOID pParam)
{
SOCKET sockfd;
sockfd = (SOCKET)pParam;
BOOL bKeepAlive = TRUE;
while (bKeepAlive)
{
fd_set rfds;
fd_set wfds;
fd_set efds;
/* 把集合清空 */
FD_ZERO(&rfds);
FD_ZERO(&wfds);
FD_ZERO(&efds);
/* 把当前连接句柄sockfd加入到集合中 */
FD_SET(sockfd, &rfds);
FD_SET(sockfd, &wfds);
FD_SET(sockfd, &efds);
/* 设置最大等待时间 */
timeval tv;
tv.tv_sec = 1;
tv.tv_usec = 0;
/* 开始等待 */
int ret = select(sockfd+1, &rfds, &wfds, &efds, &tv);
if (ret < 0)
{
TRACE("<%s> select error!\n", __FILE__);
// Sleep(100);
}
else if (ret == 0)
{
TRACE("<%s> timeout!\n", __FILE__);
PostMessage(AfxGetMainWnd()->m_hWnd,
WM_TCP_DISCONNECT, NULL, NULL);
bKeepAlive = FALSE;
}
else
{
if (FD_ISSET(sockfd, &rfds))
{
// read message
char buffer[RECV_BUFFER_SIZE];
memset(buffer, 0, sizeof(buffer));
int ret = recv(sockfd, buffer, sizeof(buffer), 0);
TRACE("<%s> DATA[%s]\n", __FILE__, buffer);
if (ret > 0)
{
PostMessage(AfxGetMainWnd()->m_hWnd,
WM_TCP_RECV_DATA, (WPARAM)buffer, NULL);
}
else if (ret == 0)
{
// 主动断开
PostMessage(AfxGetMainWnd()->m_hWnd,
WM_TCP_DISCONNECT, NULL, NULL);
bKeepAlive = FALSE;
}
else if (ret < 0)
{
// 拔掉网线
PostMessage(AfxGetMainWnd()->m_hWnd,
WM_TCP_DISCONNECT, NULL, NULL);
bKeepAlive = FALSE;
}
}
}
}
return 0;
}