2009-05-08 2 views
4

Ich implementiere ein einfaches lokales Netzwerk-Erkennungsprotokoll, also rufe ich UdpClient.Send und dann UdpClient.BeginReceive auf. Falls mehr als eine Antwort ansteht, rufe ich UdpClient.BeginReceive am Ende des Callbacks auf. Etwas wie folgt aus:Wo ist UdpClient.CancelReceive?

UdpClient client = new UdpClient(AddressFamily.InterNetwork); 
client.EnableBroadcast = true; 
client.Send(request, request.Length, broadcastEndPoint); 
client.BeginReceive(Callback, client); 

... und dann in Callback:

void Callback(IAsyncResult ar) 
{ 
    UdpClient client = (UdpClient)ar.AsyncState; 
    IPEndPoint remoteEndPoint = null; 
    byte[] response = client.EndReceive(ar, ref remoteEndPoint); 

    // Do something with response 

    client.BeginReceive(Callback, client); 
} 

Mein Problem ist, dass meine Hauptschleife client.Close ruft, während es noch aus einem Empfangs ist. Der Empfang wird abgeschlossen, und der nächste Aufruf von BeginReceive löst eine Ausnahme aus: System.Net.Sockets.SocketException: An existing connection was forcibly closed by the remote host

Warum hat UdpClient keine CancelReceive-Methode? Was kann ich stattdessen tun?

Antwort

3

Die Verwendung eines "isClosing" -Flags, um die Callback-Funktion zu benachrichtigen, dass der UdpClient nicht mehr verfügbar ist, ist keine geeignete Lösung. Da der Callback in einem anderen Thread ausgeführt wird, besteht immer die Möglichkeit, dass die Verbindung nach der Flagprüfung "isClosing" und vor dem Aufruf "BeginReceive" (oder "EndReceive") geschlossen wird.

Auch wenn das kein sauberes Design ist, scheint Microsoft zu empfehlen, nur die entsprechenden Ausnahmen abzufangen, um zu erkennen, dass der Socket nicht mehr verfügbar ist. Das ist nicht für „BeginReceive“ dokumentiert, aber das ist documented for the similar function "BeginConnect":

Um einen ausstehenden Aufruf der Beginconnect() Methode abbrechen, schließen Sie die Sockel geeignet. Wenn die Methode Close() aufgerufen wird, während eine asynchrone -Operation ausgeführt wird, wird der Callback aufgerufen, der der Methode BeginConnect() bereitgestellt wird. Ein nachfolgender Aufruf der Methode EndConnect (IAsyncResult) löst eine ObjectDisposedException aus, um anzuzeigen, dass die Operation abgebrochen wurde.

So Codebeispiel würde wie folgt aussehen:

void Callback(IAsyncResult ar) 
{ 
    try 
    { 
     UdpClient client = (UdpClient)ar.AsyncState; 
     IPEndPoint remoteEndPoint = null; 
     byte[] response = client.EndReceive(ar, ref remoteEndPoint); 

     // Do something with response 

     client.BeginReceive(Callback, client); 
    } 
    catch (SocketException e) 
    { 
     // Oups, connection was closed 
    } 
    catch (ObjectDisposedException e) 
    { 
     // Oups, client was disposed 
    } 
} 
+0

Was: UdpClient client = (UdpClient) ar.AsyncState; if (client.Client == null) return; – ajcs

6

Stattdessen oder diese Ausnahme Bool erstellen zu überwinden und setzen Sie ihn vor dem Ende Befehl ausgeben, verwenden Sie diese Bool in Callback-

wie diese

bool isClosing=false; 
void Callback(IAsyncResult ar) 
{ 
    if(isClosing) return; 
} 

die bool gesetzt isClosing vor Erteilung der Schließbefehl überprüfen