我正在尝试编写一个可以同时支持多个客户端连接的服务器,所以我正在尝试使用IOCP。让我简要介绍一下我的代码流程,然后我可以解释一下我的问题。首先,服务器正在打开一个端口用于监听和等待“接受”呼叫以获得新的传入连接。作为参考,我使用了相同的代码here所以它接受每个新的传入连接并返回一个新的套接字描述符(sd),然后它标记为非阻塞:
arg = 1;
ioctlsocket(sd, FIONBIO, &arg);
然后启用TCP_NODELAY:
level = IPPROTO_TCP;
optName = TCP_NODELAY;
value = 1;
setsockopt(sd, level, optName, (const char*)&value, sizeof(value));
此后将IOCP端口关联为:
CreateIoCompletionPort((HANDLE)sd, iocp_port, (DWORD)completion_key, 4);
completion_key是一个类对象,它只是一个容器,它包含数据缓冲区,重叠缓冲区,查询类型的recv / send等。 并在最后发出一个阅读电话:
WSARecv(sd, wsabuf, 1, &bytes, &flags, overlapped, NULL);
wsabuf和overlapped是completion_key对象的一部分。
在90%的情况下,它工作正常,即当此套接字上有一些可用的传入数据时,“GetQueuedCompletionStatus”被解除阻塞,并且它具有有效数据。但有时WSARecv调用返回错误,GetLastError()返回6,这是“无效句柄”错误。我有点困惑为什么会发生这样的事情。
我正在创建一个iocp端口:
iocp_port = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 0);
并且有一些线程正在等待“GetQueuedCompletionStatus”。
答案 0 :(得分:5)
我监控了后台发生的所有系统调用。 WSARecv在内部调用NtDeviceIoControlFile,并且有一个参数“Event”与WSARecv的lpOverlapped结构中传递的参数hEvent相同。我没有将hEvent设置为NULL,因此它获取了一些垃圾值,当它为NULL时,NtDeviceIoControlFile成功返回,而在其他情况下,它返回“INVALID_HANDLE”错误。不幸的是,它大部分时间都是NULL。