IOCP WSARecv始终返回错误10022

时间:2017-10-23 18:17:39

标签: c++ windows c++11 iocp io-completion-ports

我在Windows上使用IOCP。以前我使用方法GetQueuedCompletionStatus来轮询队列,一切都很好。但是当我决定以WSARecv调用方式使用完成例程来重构逻辑时,它始终会失败并显示错误WSAEINVAL(10022)。此代码位于使用CreateTread

创建的线程中
int flags = 0;
m_iocport = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, NULL, 0);
handle = CreateIoCompletionPort(clientSocket, m_iocport, 0, 0);
OVERLAPPED_EX *over = new OVERLAPPED_EX();
result = WSARecv(clientSocket, &over->m_wsabuf, 1, NULL, &flags, over, WorkerRoutine);

工作程序例程为空,并具有以下定义:

void static CALLBACK WorkerRoutine(DWORD Error, DWORD BytesTransferred, LPWSAOVERLAPPED Overlapped, DWORD InFlags) {}

当我将NULL而不是WorkerRoutine传递给WSARecv方法时,一切正常。但是当我将完成例程传递给调用时它失败并显示错误10022.我尝试使用WorkerRoutine&WorkerRoutine没有任何帮助。

OVERLAPPED_EX对象中的hEvent属性设置为NULL。

1 个答案:

答案 0 :(得分:2)

与文件关联的I / O完成端口和lpCompletionRoutine这是互斥参数。你不能同时使用它。当你这样做 - 内核返回STATUS_INVALID_PARAMETER,它被转换为WSAEINVAL。所以你必须得到这个错误。

IOCP和ApcRoutine 2通知您有关操作完成的不同方式。当您使用IOCP时 - 系统将数据包发送到IOCP完成。您需要稍后使用GetQueuedCompletionStatusNtRemoveIoCompletion来提取此数据包。这不是“民意调查”。从另一方面,如果您使用ApcRoutine系统插入apc到您的线程。使用两种方式同时进行通知和并发 - 这是逻辑错误,并且在这种情况下返回给你STATUS_INVALID_PARAMETER时内核正确。

遗憾的是,这在MSDN中并未明确说明,或者我最不能说明这一点。但是一些研究+ WRK源代码有助于理解这种情况:

WSARecv在内部调用ZwDeviceIoControlFile,并在内核中调用IopXxxControlFile。当lpCompletionRoutine != 0 ApcRoutine的{​​{1}}参数出现且您在this点完全失败时:

IopXxxControlFile

你也可以在堆栈中分配m_wsabuf。有效必须只是缓冲区 // // If this file has an I/O completion port associated w/it, then ensure // that the caller did not supply an APC routine, as the two are mutually // exclusive methods for I/O completion notification. // if (fileObject->CompletionContext && IopApcRoutinePresent( ApcRoutine )) { ObDereferenceObject( fileObject ); return STATUS_INVALID_PARAMETER; }

  

如果此功能以重叠方式完成,则为   Winsock服务提供商有责任捕获 WSABUF   从此调用返回之前的结构。这使应用程序   构建 lpBuffers 指向的基于堆栈的 WSABUF 数组   参数。

因此,您只能将WSABUF缓冲区放置到OVERLAPPED_EX但不是整个WSABUF.buf的缓冲区。但这与您的错误无关