Вызов WSAGetLastError () из потока IOCP возвращает неверный результат
я назвал WSARecv()
, который возвращен WSA_IO_PENDING
. Затем я послал RST
пакета с другого конца. The GetQueuedCompletionStatus()
функция, которая существует в другом потоке, вернулась FALSE
как и ожидалось, но когда я позвонил WSAGetLastError()
я получил 64
вместо WSAECONNRESET
.
почему WSAGetLastError()
не вернул WSAECONNRESET
?
Edit:
я забыл упомянуть об этом, когда я звоню WSAGetLastError()
непосредственно после сбоев WSARecv()
(из-за RST
пакет принимается), возвращается код ошибки WSAECONNRESET
, а не 64
.
похоже, что код ошибки зависит от того,WSARecv()
не удалось сразу после вызова или не удалось позже при получении пакета завершения.
1 ответов
это общая проблема с IOCP, вы делаете низкоуровневый вызов стека драйверов TCP/IP. Который, как и все драйверы в Windows, сообщает об ошибке с кодами ошибок NTSTATUS. Ожидаемая ошибка здесь-STATUS_CONNECTION_RESET.
эти собственные коды ошибок должны быть переведены в код ошибки winapi. Этот перевод обычно контекстно-зависимая, это зависит от того, какая библиотека winapi выдала команду драйвера. Другими словами, вы можете получить только Ошибка wsaeconnreset обратно, если это была библиотека Winsock, которая сделала перевод. Но это не то, что произошло в вашей программе, Это GetQueuedCompletionStatus (), который обработал ошибку.
который является общей вспомогательной функцией, которая обрабатывает IOCP для любого драйвера устройства. Нет контекста, ПЕРЕКРЫВАЮЩЕЙСЯ структуры недостаточно, чтобы указать, как начался запрос ввода-вывода. Повернись к эта статья KB, он документирует отображение по умолчанию из кодов ошибок 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
Это были, гм, не фантастические варианты. Вероятно, восходит к очень ранним окнам, когда Lanman был выбран сетевым уровнем. WSAGetLastError() довольно бессильна сопоставить ERROR_NETNAME_DELETED с конкретной ошибкой WSA, код NTSTATUS был потерян, когда GetQueuedCompletionStatus () установил код "последней ошибки" для потока. Так что это не так, это просто возвращает то, что может.
что ты ожидал является функцией 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 (). Это не очень интуитивно:)