webentwicklung-frage-antwort-db.com.de

Wie bricht man BeginReceive () von Sockets ab?

Natürlich wird BeginReceive() niemals enden, wenn es keine Daten gibt. MSDN schlägt vor dass das Aufrufen von Close()BeginReceive() abbrechen würde.

Das Aufrufen von Close() auf dem Socket führt jedoch auch eine Dispose() auf dem Socket aus, wie in this great ansewr herausgefunden, und folglich würde EndReceive() eine Ausnahme auslösen, da das Objekt bereits entsorgt ist (und es ist!).

Wie soll ich vorgehen?

39
Day_Dreamer

Es sieht so aus, als sei dies von (dem sehr dummen) Design. Sie müssen diese Ausnahme werfen und in Ihrem Code verfangen. 

MSDN sieht in der Tat still darüber aus, aber wenn Sie sich die Dokumentation einer anderen asynchronen Socket-Methode ansehen, BeginConnect () , finden wir Folgendes:

Um einen anstehenden Aufruf der BeginConnect () - Methode abzubrechen, schließen Sie den Socket. Wenn die Close () - Methode Aufgerufen wird, während eine asynchrone Operation Ausgeführt wird, wird der Rückruf Der BeginConnect () - Methode Aufgerufen. Ein nachfolgender Aufruf der EndConnect (IAsyncResult) -Methode löst Eine ObjectDisposedException auf Aus, die darauf hinweist, dass der Vorgang Abgebrochen wurde.

Wenn dies der richtige Weg für BeginConnect ist, ist dies wahrscheinlich auch für BeginReceive der Fall. Dies ist sicherlich ein schlechtes Design seitens der asynchronen API von Microsoft, da der Benutzer den Debugger ärgern würde, wenn der Benutzer die Ausnahme als Teil eines normalen Ablaufs zwingend auslösen und einfangen muss. Es ist wirklich nicht möglich, "zu warten", bis die Operation abgeschlossen ist, denn Close () ist der Abschluss.

47

Ich bin überrascht, dass niemand empfohlen hat, SocketOptions zu verwenden.

Sobald der Stack die Sende- oder Empfangsoperation hat, ist er an die Socket-Optionen des Sockets gebunden. 

Verwenden Sie ein kleines Sende- oder Empfangszeitlimit und verwenden Sie es vor der Operation, damit es Ihnen egal ist, ob es während des gleichen Vorgangs in etwas kürzeres oder längeres geändert wird. 

Dies führt zu mehr Kontextumschaltung, es ist jedoch nicht erforderlich, den Socket unter einem beliebigen Protokoll zu schließen. 

Zum Beispiel:

1) Legen Sie ein kleines Timeout fest

2) Operationen ausführen

3) Timeout größer einstellen

Dies ist vergleichbar mit der Verwendung von Blocking = false, jedoch mit einem von Ihnen angegebenen automatischen Timeout. 

2
Jay

Sie können meine Lösung für dieses Problem hier lesen (mit Kommentar von Pavel Radzivilovsky hier): UdpClient.ReceiveAsync korrigiert vorzeitige Beendigung

0
EgoPingvina

Für TCP Socket-Verbindungen können Sie die Eigenschaft Connected verwenden, um den Status des Sockets zu ermitteln, bevor Sie versuchen, auf bereitgestellte Methoden zuzugreifen. Per MSDN:

"Die Connected-Eigenschaft ruft den Verbindungsstatus des Sockets ab dem letzten E/A-Vorgang ab. Wenn sie False zurückgibt, war der Socket entweder nie verbunden oder ist nicht mehr verbunden."

Da es "nicht mehr verbunden" sagt, bedeutet dies, dass zuvor ein Close () auf dem Socket aufgerufen wurde. Wenn Sie zu Beginn des Empfangsrückrufs prüfen, ob der Socket verbunden ist, erfolgt keine Ausnahme.

0
geekus42