BOOL r = ::GetQueuedCompletionStatus(hCompletionPort, &dwBytesTransferred, (LPDWORD)&hCompletionSocket, (LPWSAOVERL APPED *) &lpOvlpEx, INFINITE);
if (hCompletionSocket== INVALID_SOCKET || lpOvlpEx == NULL)
{
Sleep(10);
continue;
}
if (!r)
{
proxy->SafeClose(lpOvlpEx);
TRACE("GetQueuedCompletionStatus error! %d\n",hSocket);
continue;
}
else if (dwBytesTransferred ==0)
{
proxy->SafeClose(lpOvlpEx);
TRACE(".....................%d..........closed & freed........\n",hSocket);
continue;
}
上面的GetQueuedCompletionStatus是接收IOCP通知的主要函数,通过dwBytesTransferred、hCompletionSocket、lpOvlpEx以及返回值r即可判断出客户端是否关闭。
但是,GetQueuedCompletionStatus不能得出网络是否异常了,比如客户端拔网线,比如突然重启,这些是无法捕获的。这是由于TCP协议本身的问题,其实细想一下,客户端还没有把数据发送缓冲区时系统就崩溃了,这种情况下肯定无法捕获的,只能通过应用协议来判断了。常用的解决方法三种:
- 定时心跳包,超时没收到回应,就认为客户端就是断开了。
- 通过SO_KEEPALIVE来判断,默认是2小时进行一次检测,自己也可以设置检测间隔,但会影响其它系统所有正在使用的Socket,慎用
- 通过SIO_KEEPALIVE_VALS,该选项不同于SO_KEEPALIVE 机制的就是它是针对单个连接的,对系统其他的Sokcet并不影响。