IOCP与SO_KEEPALIVE

项目使用IOCP完成端口,要对连入的客户端进行 死连接检测。由于是TCP协议,便想到用SO_KEEPALIVE及SIO_KEEPALIVE_VALS进行检测。简洁方便,把任务交给系统来做更有保障些。于是便写下了如下代码:

//Set Keeplive 开启保活机制
if (SOCKET_ERROR == setsockopt(pClientContext->m_sockClient, SOL_SOCKET, SO_KEEPALIVE, &chOpt, sizeof(chOpt)))
{
TRACE(_T("KeepAlive Error:0x%p\r\n"), WSAGetLastError());
return FALSE;
}
//设置超时详细信息
KeepAlive.onoff = 1;
KeepAlive.keepalivetime = 5 * 1000; //多久没有收到包
KeepAlive.keepaliveinterval = 2 * 1000; //发心跳包的频率
WSAIoctl(pClientContext->m_sockClient, SIO_KEEPALIVE_VALS, &KeepAlive, sizeof(KeepAlive), NULL, 0, &dwBytesReturned, 0, NULL);
测试发现:

正常关闭客户端,GetQueuedCompletionStatus,NumberOfBytes // bytes transferred 该值为0,可以将该客户端移除;(事实不设置SO_KEEPALIVE,也会返回0)

拔除网线,异常掉线的情况下,GetQueuedCompletionStatus  并不会返回。

后来查阅资料,得出结论:实现死连接检测,最好是自己实现一套“心跳机制”。用TCP自带的SO_KEEPALIVE不靠谱。


client一直与server保持连接,过了2、3个小时偶尔会出现这个问题,请问是什么原因呢?这段时间网络可能没有数据传输。121--信号灯超时时间已到。网上找了很久,也有人遇到,但都没有找到答案。 
参考方案
长连接,至少要实现心跳保活啊,否则即使套接字内部没有产生错误,也许你的连接也会被中间经过的某个交换机给断掉,另外客户端的重连,应该是没有什么方法能避免得了的,除非你不用TCP。

对于服务端来说,GetQueuedCompletionStatus失败了,只要返回的重叠结构指针不是NULL,你就要继续处理,即使这是一个死连接,那么也会在你最后的操作码和完成字节数中体现出来,如果重叠结构指针传回了NULL,才考虑看错误代码。
,
个人经验,tcp的keepalive不可靠,还得靠客户端的心跳机制来保持长连接
,我不知道 SO_KEEPALIVE 是怎样的一种机制,需求长连接的应用,我只知道,客户端重连是必须要做的,通常的做法都是客户端发心跳包给服务端,服务端记录时间,服务端返回一个包回去,客户端记录时间,那么不管哪一方,一旦出现超时,都是直接断开,该回收的资源回收,客户端重新考虑去连服务端,就算你使用了SO_KEEPALIVE 也是需要这么做,并不是说你简单的设置几个参数,就万事大吉什么都不用管了。

对于IOCP服务端来说 GetQueuedCompletionStatus 失败一次并不意味着你监听的那个端口就不能用了,正常情况下也不可能去操作到用来监听的套接字,那么只要客户端和服务端之间有保活机制,客户端能重连,还有什么好担心的呢?

作为程序员来说,你不用考虑TCP连接跟路由,交换机有什么关系,你只要知道,长时间没有IO数据的连接,确实是会在你经过的某些交还机或者路由器上直接断掉,如果你没有超时检测机制,这种时候,双方或其中一方会认为对方还正常连着的,但是实际上已经是一个死连接了。

转载请注明本文出处:http://www.infocool.net/kb/VC/201603/19023.html




参考链接:

http://www.infocool.net/kb/VC/201510/19023.html

http://www.itnose.net/detail/6344981.html



猜你喜欢

转载自blog.csdn.net/caichengji1/article/details/77680078
今日推荐