2010-09-02 8 views
7

Je veux utiliser UDP-Sockets pour mon XNA-Networkgame. Et maintenant j'essaie de coder un Listenerthread fiable, mais il y a quelques problèmes.C#: UDP Listener Thread

Si j'utilise socket.Receive attendra un paquet. C'est bon pour mon Listenerthread. Mon fils a un certain temps en boucle comme ceci:

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

Mais si j'échange Listen-Flag false (si je veux arrêter d'écouter), il sera coincé dans la dernière .Receive().

Puis j'ai regardé les méthodes .BeginReceive(). Il appellera une méthode si un paquet est arrivé. Mais pour recevoir les données, je dois utiliser .EndReceive() et c'est le point avec lequel j'ai un problème. Je veux toujours écouter les paquets et n'arrête pas d'écouter si un paquet arrive. Donc, j'utilise toujours la version bloquante avec ".Receive()". Je pourrais forcer le thread d'écoute à annuler en appelant: Thread.abort(), mais ce n'est pas bon.

Actuellement je teste si les données sont disponibles:

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

Mais je pense que ce n'est pas la meilleure façon ... Si peu de temps après l'article si un autre thread appelle socket.Receive (..) il restera coincé involontairement. N'y a-t-il aucun moyen d'annuler la méthode .Receive (..)? J'ai essayé de définir un délai d'attente, mais si .Receive timesout, il lèvera une exception ...

Je veux un simple udp-écoute-thread, je peux arrêter gracieusement. :-) Dans MSDN je n'ai pas trouvé un exemple d'écouteur qui écoute plus d'un paquet. Comment gérer un autre programmeur cela?

+0

« Si peu de temps après l'article si un autre thread appelle socket.Receive (..) » - cela semble impliquer qu'il ya plusieurs threads de lecture à partir de la même prise? – Ragoczy

+0

Non, je ne fais pas ça. Mais c'est possible et je veux éviter cela :-) – user437899

+1

Lorsque vous êtes prêt à arrêter d'écouter, fermez le socket. Le blocage 'Receive()' quittera avec une exception 'SocketException' que vous devrez attraper. –

Répondre

9

Marquez le drapeau Listen comme volatil, afin que les modifications puissent être visibles entre les threads.

public volatile bool Listen{get; set;} 

Gérer les exceptions appropriées dans votre fil:

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(); 

Dans le code où vous passez le drapeau Listen à false vous pouvez soit fermer la prise ou vous interrompez le fil:

Listen = false; 

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

Merci Lirik et Matt Davis. Cela fonctionne bien, mais est-ce correct d'utiliser des exceptions pour cela? J'ai appris que des exceptions ne devraient être lancées que si quelque chose de mauvais/inattendu se produit. (pour arrêter la méthode de blocage est prévu :-))

J'ai géré l'exception comme ceci. Je cherche le code d'erreur puis je casse la boucle.

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

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

Pourquoi je dois utiliser

socket.Shutdown(SocketShutdown.Both); 

avant

socket.Close(); 

Est-ce que .close() pas arrêter la prise ainsi?

Et si je veux à nouveau utiliser le socket, y a-t-il un "redémarrage" -méthode ou dois-je créer une nouvelle instance de socket?

Salutations user437899

+0

Il est parfaitement possible d'utiliser une exception pour sortir d'un appel bloquant, alors ne craignez pas l'exception! L'arrêt arrête l'envoi et la réception, mais Close va "éteindre" le socket mais de manière forcée. Si vous souhaitez réutiliser le socket, appelez Disconnect au lieu de Close. – Kiril