2010-10-12 5 views
1

J'écris un serveur de jeu qui a une limite de temps. J'accepterai l'entrée à travers une douille jusqu'à ce que le temporisateur soit fait. J'utilise une boucle pour toujours recevoir des données du client.Comment rompre une boucle qui s'exécute dans un thread différent en utilisant un TimerCallback en C#?

while(true) 
{ 
    socket.Receive(buffer); 
} 

Je dois sortir de cette boucle lorsque la limite de temps se termine. Désolé, je ne pense pas que je suis assez spécifique.

J'ai deux lecteurs qui envoient et reçoivent des données de manière asynchrone. La minuterie est utilisée pour garder une trace de l'heure pour les deux joueurs. Je dois terminer la réception des données des deux joueurs et redonner des statistiques sur leur jeu à la fin de la minuterie. Avoir une minuterie chien de garde fermer le socket lorsque le délai expire.

+1

La meilleure façon de faire cela est généralement d'avoir le fil de police lui-même et de fournir un mécanisme de contrôle. L'interruption du fil devient souvent poilue autrement. –

+0

Pourrais-je simplement tuer le fil si la minuterie s'éteint? – Ge3ng

+0

Mieux tuer le client plutôt que le fil, comme je viens de le suggérer dans ma réponse. Lorsque vous obtenez SocketException, vous pouvez gérer l'erreur et effectuer des actions correctives –

Répondre

2

La meilleure façon de gérer cela est que le temporisateur appelle une méthode d'arrêt dans la classe où la méthode de réception socket est. Cette classe aura une instance de membre AutoResetEvent et dans le temps pour la prise lecture vérifiez l'événement pour voir si vous devez arrêter:

public class SomeClass { 
    AutoResetEvent _stopEvent = new AutoResetEvent(false); 
    Socket _socket; 
    public void StopReceive() { 
     _stopEvent.Set(); 
    } 
    private void SomeMethod() { 
     _socket.ReceiveTimeout = 5000; // In milliseconds 
     while(!_stopEvent.WaitOne(0)){ 
       _socket.Receive(buffer); 
     } 
    } 
} 

Edit: Si vous avez deux prises pour les deux joueurs sur deux sujets différents Avec le troisième thread qui gère le délai, le code des trois threads doit accéder au même événement et modifier l'événement en ManualResetEvent. Ce dont je ne suis pas sûr, c'est si vous avez une classe qui gère le thread minuteur, et une autre classe qui gère les threads de lecture socket pour les deux joueurs, ou si elles sont gérées par une classe. Si ce sont des classes séparées, puis le code ci-dessus, vous pouvez passer l'événement dans le constructeur:

public class SomeClass { 
    ManualResetEvent _stopEvent; 
    Socket _socket; 
    public SomeClass(ManualResetEvent stopEvent) { 
     _stopEvent = stopEvent; 
    } 
    private void SomeMethod() { 
     _socket.ReceiveTimeout = 5000; // In milliseconds 
     while(!_stopEvent.WaitOne(0)){ 
       _socket.Receive(buffer); 
     } 
    } 
} 

Le fil de la minuterie peut maintenant appeler la méthode Set() dans l'instance ManualResetEvent et les deux boucles en cesseraient.

+0

Cela ne fonctionnera pas parce que j'ai 2 joueurs et ils envoient des données simultanément. J'ai besoin d'une minuterie pour gérer l'ensemble du jeu. – Ge3ng

+0

Je ne suis pas sûr de comprendre, si vous voulez dire que vous avez deux sockets et donc deux boucles while, alors les deux boucles while devraient utiliser le même événement, et le thread timeout pourrait appeler l'événement set. Sans connaître un peu plus la structure de votre code, je ne sais pas comment procéder. –

+0

Ouais j'ai deux prises, une pour chaque joueur et elles sont l'une de leur propre thread. Le jeu a son propre thread qui gère l'envoi d'informations aux clients. J'ai besoin que le jeu mette fin aux deux boucles while lorsque la minuterie se termine. – Ge3ng

0

Il provoquera une exception SocketException sur votre socket.Receive appelez donc être préparé pour l'attraper. J'utilise le même mécanisme à des fins différentes.

Solution 2: http://msdn.microsoft.com/en-us/library/system.net.sockets.socket.receivetimeout.aspx mais je ne sais pas s'il peut être appliqué à votre cas. Ou, sinon, vous pouvez interroger la propriété Available du socket qui indique combien d'octets sont prêts à être lus. Mais cela implique un sondage/spinlock, ce qui est mauvais pour la performance. Même si vous vouliez utiliser un sémaphore, ce qui vous donne la possibilité de définir un délai maximum, vous avez toujours besoin de "quelqu'un" pour le libérer lorsque les données sont disponibles

0

Je pensais qu'au lieu de créer une boucle infinie. Je pourrais éventuellement utiliser une prise non bloquante.

while(stillTime) 
{ 
    if(socket.Available > 0) 
    socket.Recieve(buffer); 
} 

Et lorsque la minuterie est désactivée, définissez stillTime sur false.

Est-ce une meilleure solution?

Questions connexes