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 完成。您稍后需要使用 GetQueuedCompletionStatus
或 NtRemoveIoCompletion
来提取此数据包。这不是 "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
。但这已经与你的错误无关
我在 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 完成。您稍后需要使用 GetQueuedCompletionStatus
或 NtRemoveIoCompletion
来提取此数据包。这不是 "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
。但这已经与你的错误无关