Der Aufruf von WSAGetLastError () von einem IOCP-Thread gibt ein falsches Ergebnis zurück

8

Ich habe WSARecv() aufgerufen, was WSA_IO_PENDING zurückgegeben hat. Ich habe dann ein RST -Paket vom anderen Ende gesendet. Die Funktion GetQueuedCompletionStatus() , die in einem anderen Thread existiert, hat FALSE erwartungsgemäß zurückgegeben, aber wenn ich WSAGetLastError() aufgerufen habe, habe ich 64 anstelle von WSAECONNRESET .

erhalten

Also warum WSAGetLastError() hat WSAECONNRESET nicht zurückgegeben?

Bearbeiten:

Ich habe vergessen zu erwähnen, dass wenn ich WSAGetLastError() direkt nach einem fehlgeschlagenen WSARecv() aufruft (wegen eines empfangenen RST Pakets), ist der zurückgegebene Fehlercode WSAECONNRESET und nicht 64 .

Es sieht also so aus, als ob der zurückgegebene Fehlercode davon abhängt, ob WSARecv() direkt nach dem Aufruf fehlgeschlagen ist oder später beim Abrufen eines Completion-Pakets fehlgeschlagen ist.

    
Tom 08.03.2015, 09:32
quelle

1 Antwort

12

Dies ist ein generisches Problem bei IOCP. Sie führen einen Low-Level-Aufruf an den TCP / IP-Treiberstapel durch. Welche, wie alle Treiber in Windows tun, melden Fehler mit NTSTATUS-Fehlercodes. Der erwartete Fehler ist hier STATUS_CONNECTION_RESET.

Diese nativen Fehlercodes müssen in einen winapi-Fehlercode übersetzt werden. Diese Übersetzung ist normalerweise kontextsensitiv , sie hängt davon ab, welche winapi-Bibliothek den Treiberbefehl ausgegeben hat. Mit anderen Worten, Sie können einen WSAECONNRESET-Fehler immer nur dann zurückerhalten, wenn die Winsock-Bibliothek die Übersetzung ausgeführt hat. Aber das ist nicht in Ihrem Programm passiert, es war GetQueuedCompletionStatus (), das den Fehler behandelte.

Dies ist eine generische Hilfsfunktion, die IOCP für jeden Gerätetreiber behandelt. Es gibt keinen Kontext, die OVERLAPPED-Struktur ist nicht annähernd genug, um anzuzeigen, wie die I / O-Anforderung gestartet wurde. Wechseln Sie zu diesem KB-Artikel , es dokumentiert die Standardzuordnung von NTSTATUS-Fehlercodes zu winapi-Fehlercodes. Die Zuordnung, die GetQueuedCompletionStatus () verwendet. Relevante Einträge in der Liste sind:

%Vor%

Das waren, ahem, keine fantastischen Entscheidungen. Geht wahrscheinlich auf sehr früh Windows zurück, als Lanman die Netzwerkschicht der Wahl war. WSAGetLastError () ist ziemlich machtlos, ERROR_NETNAME_DELETED einem WSA-spezifischen Fehler zuzuordnen, der NTSTATUS-Code ging verloren, wenn GetQueuedCompletionStatus () den "letzten Fehler" -Code für den Thread festlegte. So ist es nicht, es gibt nur zurück, was es kann.

Was Sie erwarten würden ist eine WSAGetQueuedCompletionStatus () - Funktion, so dass diese Fehlerübersetzung unter Verwendung von Winsock-Regeln korrekt passieren kann. Es gibt keinen. In diesen Tagen verwende ich lieber die ultimative Autorität, um Windows-Code richtig zu schreiben, die .NET Framework-Quelle, wie sie von der Referenzquelle . Ich bin mit der Quelle für die SocketAsyncEventArgs.CompletionCallback () -Methode verbunden. Welche enthält den Schlüssel:

%Vor%

Oder mit anderen Worten, Sie müssen einen extra Aufruf an WSAGetOverlappedResult () vornehmen, um den richtigen Rückgabewert von GetLastError () zu erhalten. Das ist nicht sehr intuitiv:)

    
Hans Passant 11.03.2015, 10:11
quelle

Tags und Links