Вызов 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 (). Это не очень интуитивно:)