c++ - IOCP WSARecv 总是返回错误 10022

标签 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 没有任何帮助。

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

最佳答案

与文件关联的 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 IopXxxControlFileApcRoutine 参数存在时,您恰好在 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。但这已经与您的错误无关

关于c++ - IOCP WSARecv 总是返回错误 10022,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46895956/

相关文章:

c++ - WinRT C++ : get package family name

c++ - 是否有类似 MATLAB 的 OpenCV 颜色条的东西?

windows - 如何在 Windows 上的 Eclipse Juno 中为 C/C++ 设置调试器

c++ - lambda 内的编译器的模板类型不是 "seen"

c++ - 变体类型和可变参数模板的转换和输出运算符

c++ - 使用 shared_ptr : C++ 管理多个对象

c++ - 创建类型特征以检测 C++ 中的仿函数

c++ - 使用 ASSIMP 和 GLSL 的骨骼动画 : bone uniform array size

c++ - 我们可以从 C++ 代码中禁用麦克风吗

c# - 为绘制的对象添加事件监听器