2010-09-02 19 views
7

Chcę używać UDP-Sockets dla mojej XNA-Networkgame. A teraz próbuję kodować niezawodny Listenerthread, ale są pewne problemy.C#: UDP Listener Thread

Jeśli użyję socket.Receive będzie czekać do pakietu. To jest dobre dla mojego Listenerthread. Mój wątek ma chwilę pętli tak:

while(Listen == true) 
{ 
    socket.Receive(...); 
} 

Ale gdybym zamienić listen-Flag na false (jeśli chcę przestać słuchać), będzie on zatrzymany w ostatnim .Receive().

Potem przyjrzałem się Methodes .BeginReceive(). Wywoła metode, jeśli nadejdzie pakiet. Ale aby otrzymać dane, które muszę użyć .EndReceive() i to jest punkt, z którym mam problem. Chcę nadal słuchać pakietów i nie przestawać nasłuchiwać, jeśli nadejdzie pakiet.

Nadal używam wersji blokującej z ".Receive()". Mogłem wymusić anulowanie wątku odsłuchowego przez wywołanie: Thread.abort(), ale nie jest to dobre.

Obecnie sprawdzić, czy dane są dostępne:

while(Listen == true) 
{ 
    if(socket.Available > 0) 
    { 
     socket.Receive(...); 
    } 
} 

Ale myślę, że to nie jest najlepszy sposób ... Jeśli wkrótce po IF-klauzuli inny wątek dzwoniącej socket.Receive (..) znowu utknie w nieumyślnym. Czy nie ma możliwości anulowania metody .Receive (..)? Próbowałem ustawić limit czasu, ale jeśli .Receive timeout, to wyrzuci wyjątek ...

Chcę prostego wątku słuchania, mogę zatrzymać się z wdziękiem. :-) W MSDN nie znalazłem listenera - przykład, który nasłuchuje więcej niż jednego pakietu. Jak obsługiwać to inne programistę?

+0

„Jeśli zaraz po IF-klauzuli inny wątek dzwoni socket.Receive (..)” - to wydaje się sugerować, że istnieje wiele wątków odczytu z tego samego gniazda? – Ragoczy

+0

Nie, nie robię tego. Ale jest to możliwe i chcę tego uniknąć :-) – user437899

+1

Gdy jesteś gotowy, aby przestać słuchać, zamknij gniazdo. Metoda blokująca 'Receive()' zakończy działanie z 'SocketException', który musisz przechwycić. –

Odpowiedz

9

Oznacz flagę Listen jako zmienną, więc zmiany mogą być widoczne między wątkami.

public volatile bool Listen{get; set;} 

Uchwyt odpowiednie wyjątki w swoim wątku:

Thread listener = new Thread(()=> 
{ 
    while(Listen == true) 
    { 
     try 
     { 
      socket.Receive(); 
     } 
     catch(ThreadInterruptException) 
     { 
      break; // exit the while loop 
     } 
     catch(SocketException) 
     { 
      break; // exit the while loop 
     } 
    } 
}); 
listener.IsBackground = true; 
listener.Start(); 

w kodzie gdzie jesteś przełączania flagę Listen do false trzeba albo zamknąć gniazdo lub przerwać wątek:

Listen = false; 

socket.Shutdown(SocketShutdown.Both); 
socket.Close(); 
// 
// OR 
// 
listener.Interrupt(); 
1

Dziękuję Lirik i Matt Davis. Działa dobrze, ale czy można używać wyjątków? Nauczyłem się, że wyjątki powinny być odrzucane tylko wtedy, gdy wydarzy się coś złego/nieoczekiwanego. (aby zatrzymać metodę blokowania :-))

Podjęłam wyjątek w ten sposób. Szukam kodu błędu, a następnie przerywam pętlę.

   try 
       { 
        broadcastSocket.ReceiveFrom(returnData, ref ep); 

        //... 
       } 
       catch (SocketException ex) 
       { 
        if (ex.ErrorCode == 10004) 
        { 
         break; 
        } 
       } 

Dlaczego muszę używać

socket.Shutdown(SocketShutdown.Both); 

przed

socket.Close(); 

Will .close() nie zamknięcie gniazda, jak również?

A jeśli chcę ponownie użyć gniazda, czy jest "Restart" -methode lub muszę utworzyć nowy socketinstance?

Pozdrowienia user437899

+0

Całkowicie dobrze jest użyć wyjątku, aby wyjść z blokady, więc nie bój się wyjątku! Shutdown zatrzymuje wysyłanie i odbieranie, ale Close "zamknie" gniazdo, ale w sposób wymuszony. Jeśli chcesz ponownie użyć gniazda, wywołaj Disconnect zamiast Close. – Kiril