IOCP WSARecv 总是 return 错误 10022

IOCP WSARecv always return error 10022

我在 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 没有任何帮助。

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

与文件关联的I/O完成端口和lpCompletionRoutine这是互斥的参数。你不能同时使用它们。当你这样做时 - 内核 return STATUS_INVALID_PARAMETER 被翻译成 WSAEINVAL。所以你一定得到了这个错误。

IOCP 和 ApcRoutine 2 种不同的方式通知您操作完成。当你使用 IOCP - 系统发送数据包到 IOCP 完成。您稍后需要使用 GetQueuedCompletionStatusNtRemoveIoCompletion 来提取此数据包。这不是 "poll"。如果您使用 ApcRoutine 系统,则从另一方面将 apc 插入您的线程。使用两种方式立即和并发通知 - 这是逻辑错误,内核在 return 对你 STATUS_INVALID_PARAMETER 在这种情况下是正确的。

不幸的是,这在 MSDN 中没有明确说明,或者我无法找到它的最低限度。但一些研究+ WRK源代码有助于理解这种情况:

WSARecv 内部调用 ZwDeviceIoControlFile 结果内核调用 IopXxxControlFile. when lpCompletionRoutine != 0 the ApcRoutine parameter for IopXxxControlFile is present and you fail exactly at this 点:

    //
    // 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;
}

您也可以在堆栈中分配 m_wsabuf。 valid 必须是 WSABUF

的唯一缓冲区

If this function is completed in an overlapped manner, it is the Winsock service provider's responsibility to capture the WSABUF structures before returning from this call. This enables applications to build stack-based WSABUF arrays pointed to by the lpBuffers parameter.

所以你可以放置到 OVERLAPPED_EX 只缓冲到 WSABUF.buf 点而不是整个 WSABUF。但这已经与你的错误无关