从 IOCP 线程调用 WSAGetLastError() 将返回不正确的结果
Calling WSAGetLastError() from an IOCP thread return incorrect result
我调用了返回WSA_IO_PENDING
WSARecv()
。然后,我从另一端发送了一个RST
数据包。存在于另一个线程中的 GetQueuedCompletionStatus()
函数按预期返回了FALSE
,但是当我调用WSAGetLastError()
时,我得到了64
而不是WSAECONNRESET
。
那么WSAGetLastError()
为什么没有WSAECONNRESET
回来呢?
编辑:
我忘了提到,当我在WSARecv()
失败后直接呼叫WSAGetLastError()
时(因为收到RST
数据包),返回的错误代码是WSAECONNRESET
而不是64
。
因此,看起来返回的错误代码取决于WSARecv()
是在调用它后直接失败,还是稍后在检索完成数据包时失败。
这是 IOCP 的一般性问题,您正在对 TCP/IP 驱动程序堆栈进行低级别调用。 与Windows中的所有驱动程序一样,它报告失败并带有NTSTATUS错误代码。 此处的预期错误是STATUS_CONNECTION_RESET。
这些本机错误代码需要转换为 winapi 错误代码。 此转换通常是上下文相关的,这取决于哪个 winapi 库发出了驱动程序命令。 换句话说,只有当是Winsock库执行翻译时,您才能返回WSAECONNSET错误。 但这不是程序中发生的事情,而是 GetQueuedCompletionStatus() 处理了错误。
这是一个通用帮助程序函数,用于处理任何设备驱动程序的 IOCP。 没有上下文,重叠结构不足以指示 I/O 请求是如何开始的。 转到此知识库文章,它记录了从 NTSTATUS 错误代码到 winapi 错误代码的默认映射。 GetQueuedCompletionStatus() 使用的映射。列表中的相关条目包括:
STATUS_NETWORK_NAME_DELETED ERROR_NETNAME_DELETED
STATUS_LOCAL_DISCONNECT ERROR_NETNAME_DELETED
STATUS_REMOTE_DISCONNECT ERROR_NETNAME_DELETED
STATUS_ADDRESS_CLOSED ERROR_NETNAME_DELETED
STATUS_CONNECTION_DISCONNECTED ERROR_NETNAME_DELETED
STATUS_CONNECTION_RESET ERROR_NETNAME_DELETED
这些,咳咳,不是梦幻般的选择。 可能可以追溯到非常早期的Windows,当时Lanman是首选的网络层。 WSAGetLastError() 非常无力将ERROR_NETNAME_DELETED映射回 WSA 特定错误,当 GetQueuedCompletionStatus() 为线程设置"最后一个错误"代码时,NTSTATUS 代码丢失了。 所以它没有,它只是返回它能返回的内容。
你所期望的是一个WSAGetQueuedCompletionStatus()函数,以便使用Winsock规则正确进行此错误转换。 没有之一。 如今,我更喜欢使用如何正确编写Windows代码的最终权威,即可从参考源代码中获得的.NET Framework源代码。 我链接到 SocketAsyncEventArgs.CompletionCallback() 方法的源代码。 其中包含密钥:
// The Async IO completed with a failure.
// here we need to call WSAGetOverlappedResult() just so Marshal.GetLastWin32Error() will return the correct error.
bool success = UnsafeNclNativeMethods.OSSOCK.WSAGetOverlappedResult(
m_CurrentSocket.SafeHandle,
m_PtrNativeOverlapped,
out numBytes,
false,
out socketFlags);
socketError = (SocketError)Marshal.GetLastWin32Error();
换句话说,您必须对WSAGetOverlappedResult()进行额外的调用才能从GetLastError()获取正确的返回值。 这不是很直观的:)
- 在C++中返回不正确的楼层函数值
- wcslen() 在使用编译指示包时返回不正确的结果
- 当我输入分数值时,它返回不正确的结果
- ifstream::read 不断返回不正确的值
- C++ 中的 MD5 实现返回不正确的摘要
- MSVC OSVersion 返回不正确的版本
- 'SystemParametersInfo'函数在获取桌面壁纸时返回不正确的值
- c++winsock-recv()返回不正确且奇怪的缓冲区
- Winsock recv() 返回不正确的数据
- C sizeof自定义类返回不正确的值
- 带有绝对路径的LoadLibrary返回不正确的HMODULE,没有任何错误
- 检查两个数组中的相似元素,为某些测试返回正确的值,为其他测试返回不正确的值
- 使用 const 指针的 C 样式字符返回不正确的结果
- Intel TBB parallel_reduce返回不正确的结果
- GetPixel返回不正确的值
- 从 IOCP 线程调用 WSAGetLastError() 将返回不正确的结果
- 计算后缀表达式.pop() 返回不正确的值来计算函数
- 在具有 64 位 CPU 的 32 位 Win8 上运行 32 位 Orwell Dev-C++ - 输入指针返回不正确
- IDirectSound8 setCooperativeLevel 返回不正确的参数
- GetSystemMetrics(SM_CYVIRTUALSCREEN) 返回不正确的高度