2010-05-29 7 views
1

Je travaille actuellement sur un outil d'interdiction IP pour les premières versions de Call of Duty 1. (Apparemment, une telle fonctionnalité n'a pas été implémentée dans ces versions). J'ai terminé une application à un seul thread mais cela ne fonctionnera pas assez bien pour plusieurs serveurs, c'est pourquoi j'essaye d'implémenter le threading.Serveurs de relève sur le même port - Threads et Java

Actuellement, chaque serveur a son propre thread. J'ai une classe de réseautage, qui a une méthode; "GetStatus" - cette méthode est synchronisée. Cette méthode utilise DatagramSocket pour communiquer avec le serveur. Comme cette méthode est statique et synchronisée, je ne devrais pas avoir de problèmes et recevoir tout un tas d'exceptions "Adresse déjà utilisée".

Cependant, j'ai une deuxième méthode appelée "SendMessage". Cette méthode est supposée envoyer un message au serveur. Comment puis-je m'assurer que "SendMessage" ne peut pas être invoqué quand il y a déjà un thread dans "GetStatus", et inversement? Si je fais les deux synchronisés, je vais quand même avoir des ennuis si Thread A ouvre une socket sur le port 99999 et appelle "SendMessage" alors que Thread B ouvre une socket sur le même port et appelle "GetStatus"? (Les serveurs de jeu sont généralement hébergés sur les mêmes ports)

Je suppose que je cherche réellement à synchroniser une classe entière, de sorte qu'une seule méthode puisse être appelée et exécutée à la fois par un seul thread.

Espérons que ce que j'essaie d'accomplir/d'éviter est clair dans ce texte.

Toute aide est grandement appréciée.

+1

btw, 99999 n'est pas un port valide - les ports sont des nombres non signés de 16 bits – mdma

+0

À quoi sont-ils synchronisés SendMessage et GetStatus? – Kiril

+0

Port 99999 était juste un exemple, me diriez-vous que "Port XXXXX" n'est pas un port valide aussi si j'avais écrit cela? Qu'en est-il de "Port "? – John

Répondre

2

En ce moment, chaque serveur possède son propre fil. Pourquoi avez-vous besoin de deux serveurs dans la même application?!?

Pourquoi avez-vous besoin de deux serveurs dans la même application?!? Si vous séparez les deux serveurs en application distincte, vous aurez toujours le même problème si les deux essaient d'utiliser le même port ... c'est-à-dire que vous devez dédier un port à chaque serveur. Si c'est vraiment un problème avec le thread, alors lisez ci-dessous pour des idées sur la façon de résoudre ce problème.

Il est impossible pour deux threads pour exécuter correctement les méthodes synchronisées de la même classe ... si vous avez une bonne synchronisation alors il n'y a aucun moyen de vivre ce que vous décrivez. Voici ce que votre classe devrait ressembler à:

class Networking 
{ 
    public synchronized Status getStatus() { 
     Status stat = new Status(); 
     // ... 
     // Get status logic 
     // ... 
     return stat;// return the status 
    } 

    public synchronized void sendMessage(Message msg) { 
     // ... 
     // Send the message logic 
     // ... 
    } 
} 

Donc, tant que vous invoquer ces méthodes sur la même Networking exemple (vous ne disposez pas d'une instance distincte de la classe Networking pour chaque fil), alors vous ne devriez pas voir de problèmes.Voici ce que le mot-clé synchronized fait pour vous:

Tout d'abord, il est impossible pour deux appels de méthodes synchronisées sur le même objet à entrelacer. Lorsque un fil exécute un procédé synchronisé pour un objet, tous les autres fils qui synchronisés invoquer des méthodes pour le même bloc d'objet (suspendre l'exécution) jusqu'à ce que le premier fil se fait avec l'objet.

Deuxièmement, lorsqu'un sorties de méthode synchronisée, il établit automatiquement une passe-avant relation avec un appel ultérieur d'un procédé synchronisé pour le même objet . Cela garantit que les modifications à l'état de l'objet sont visibles à tous les threads. (ref)

Si vous voulez avoir la synchronisation des méthodes à travers toutes les instances de la classe de réseau, vous devez utiliser des instructions de synchronisation:

class Networking 
{ 
    private static final Object lock = new Object(); 

    public synchronized Status getStatus() { 
     synchronized(lock){ 
      Status stat = new Status(); 
      // ... 
      // Get status logic 
      // ... 
      return stat;// return the status 
     } 
    } 

    public synchronized void sendMessage(Message msg) { 
     synchronized(lock){ 
      // ... 
      // Send the message logic 
      // ... 
     } 
    } 
} 
0

Je pense que vous pourriez mal interpréter le fonctionnement des sockets et confondre les extrémités des sockets client et serveur. Si vous envoyez un message, cela se fait généralement à partir d'un socket client. Ceux-ci ne sont pas liés à un numéro de port statique - c'est le socket serveur (celui que vous appelez accept() on) qui est lié à un port spécifique.

Vous pouvez avoir autant de clients que vous le souhaitez (jusqu'à une limite raisonnable - il y a un maximum de 60 000 connexions client) depuis n'importe quelle interface réseau.

Pour une introduction aux prises côté client et serveur, consultez la leçon Sun: All About Sockets

+0

Vous n'appelez pas 'accept' sur une socket UDP, seulement sur un socket TCP. –

+0

Droit - Je n'ai pas vu que c'était une socket datagramme. – mdma

2

vais [I] encore avoir des ennuis si thread A est l'ouverture d'un socket sur le port 99999 et invoquant "SendMessage" tandis que le thread B ouvre une socket sur le même port et invoquant "GetStatus"?

Il y a deux questions distinctes ici. (Au-delà du fait que 99999 n'est pas un port valide #)

UDP par sa nature est destiné à un multiplexe à de nombreuses communications de style. Vous pouvez ouvrir une seule socket et utiliser cette socket unique pour communiquer avec autant de serveurs que vous le souhaitez. Vous n'avez pas à vous soucier de la synchronisation dans le sens d'un thread d'envoi et d'un autre sur le même socket ou de deux threads essayant d'envoyer simultanément car les opérations de lecture et d'écriture sur le socket sont atomiques du point de vue des applications. Lorsque vous envoyez sur un socket UDP vous invoquez un appel système qui copie N octets de données de l'espace mémoire de l'application dans une mémoire tampon dans l'espace mémoire du noyau du système d'exploitation, et le noyau rassemble ces données dans un paquet UDP qui est mis sur une file d'attente pour l'envoi - tout d'une manière qui semble atomique à l'application. La même chose se produit lors de la lecture à partir d'une socket UDP sauf en inverse; des paquets distincts existent dans un tampon de réception dans le noyau et lorsque votre application lit le socket, les données de ces paquets sont copiées de manière atomique depuis le tampon du noyau dans le tampon de votre application, un paquet par opération de lecture.

La deuxième question est la gestion des données entrantes et sortantes vers des serveurs spécifiques. Il semble que vous vouliez avoir un thread par serveur qui maintient l'état/statut concernant ce serveur. Lors de l'envoi, vous n'avez pas à vous soucier de la synchronisation. Tous les threads peuvent envoyer à partir du même socket et la synchronisation est efficacement gérée par le noyau du système d'exploitation.

Cependant, la réception est une question complètement différente. Je recommande d'avoir un thread dont le seul travail est de lire les paquets entrants hors de la socket et de les démultiplexer. Chaque thread de serveur aurait une file d'attente de thread dans laquelle le thread de lecteur copierait les paquets entrants. Ensuite, chaque thread de serveur n'a pas à se soucier de quoi que ce soit d'autre que de lire les paquets de sa propre file d'attente de paquets entrants - il n'a pas du tout à lire avec le socket.

Questions connexes