[C#][Sockets] Ecouter plusieurs clients

Signaler
Messages postés
35
Date d'inscription
samedi 26 février 2005
Statut
Membre
Dernière intervention
12 août 2006
-
Messages postés
10
Date d'inscription
mardi 17 juin 2008
Statut
Membre
Dernière intervention
8 juillet 2008
-
Bonjour,
Je travaille en ce moment sur un petit programme de chat
Je recontre un problème pour la connection de plusieurs clients

Lorsqu'un seul client se connecte ca fonctionne bien mais lorsqu'un deuxieme essai, ses messages ne sont pas pris en compte.
Je me pose la question suivante:
Est ce que je dois instancier un TcpListener pour chaque client du coté serveur ou un seul suffit pour tous?

Voici ce que je fais du coté serveur

Lorsqu'il demarre
IPEndPoint ipServerEndPoint = new IPEndPoint(IPAddress.Parse("127.0.0.1"), port);

// initialisation de la socket d'ecoute
socket_ecoute = new TcpListener(ipServerEndPoint);

// Mise en marche de la socket
socket_ecoute.Start();
                       
// Creation d'une thread au chargement associé a la fontion Ecoute()
th = new Thread(new ThreadStart(Ecoute));
th.Start() ;
Console.WriteLine("Chat demarré et sur ecoute");

public void Ecoute()
        {
  
                MySocket = socket_ecoute.AcceptSocket();
     
                //attente de donnée arrivant du Client avec une boucle infinie
                while(stop)
                {

                    // on met les bytes recuperé dans le tableau
                   
                        // Creation d'un tableu de byte pour contenir les donnés reçu
                        Byte[] buffer = new Byte[1024];
                       
                        MySocket.Receive(buffer);

                        //On traduit les Bytes en caractère ASCII lisible
                        string data = Encoding.ASCII.GetString(buffer).TrimEnd('\0');

                        // On envoi le texte aux clients
                        if (data != "")
                        {
                            Console.WriteLine(data);

                            EnvoieAuClient(MySocket, data);

                        }

                }

}

Merci :)

18 réponses

Messages postés
3466
Date d'inscription
lundi 16 octobre 2000
Statut
Modérateur
Dernière intervention
30 octobre 2008
46
Salut

C'est normal. La facon dont tu as structuré le serveur te permet d'accepter qu'un seul client

En fait tu n'as besoin de qu'un TCPListener.
Cependant, il faut boucler sur le AcceptSocket();

Quand un Client se connecte, AcceptSocket te retourne un socket, qui te permet de connecter avec le client. Il faut que tu stockes ce Socket (tableau, List<Socket>, ou autre).
Mais il faut ensuite que tu rappelles AcceptSocket(); pour tous les clients qui se connecteront par la suite.

Donc en gros, il te faut un Thread d'ecoute de connexion des clients et qui ne fait que ca, en boucle, et un autre thread (ou plusieurs) qui te permettent la communication avec ces clients

Petite fonction d'exemple dans un de mes codes
J'avais une Classe Client qui me permettait de stocker toutes les infos sur eux (Socket, identifiants, ...)
Je stockait chaque client dans une List<Client>
Cette fontion etait appelée dans un Thread de la meme facon que toi tu le fais dans ton code.

<hr />

private
void ListenToClients()
{

   Console.WriteLine(
"En attente de clients...");

   while (listen)
   {

         // La méthode AcceptSocket est bloquante, donc tant qu'il n'y a pas de connexion
         // l'execution de la méthode s'arrete a cette ligne
         Socket socket =
this.tcpListener.AcceptSocket();

         Console.WriteLine(
string.Format(
"Connexion du client {0}",
this.idClient));

         lock (
this.clientsList)
         {

            // On cree un nouveau client
            Client client =
new
Client(socket, idClient++);

            // On l'ajoute a notre liste de clients
            this.clientsList.Add(client);
         }
   }
}
<hr />

Mx
MVP C# 
Messages postés
35
Date d'inscription
samedi 26 février 2005
Statut
Membre
Dernière intervention
12 août 2006

Donc si j'ai bien compris mon code est bon sauf pour le stockage du Socket.

Plutôt que d'utiliser MySocket, il faut que je stock socket_ecoute.AcceptSocket(); dans un tableau à chaque fois qu'un nouveau client se connecte.

Seulement il y a quelque chose qui me gène
Si dans mon thread je fais :

listeSockets.Add(socket_ecoute.AcceptSocket());

Ca va me faire un ArrayList qui va augmenter sans cesse...?
Messages postés
3466
Date d'inscription
lundi 16 octobre 2000
Statut
Modérateur
Dernière intervention
30 octobre 2008
46
Il te faut un Socket de communication par clients, donc il n'y a rien d'anormal a ca.

Mx
MVP C# 
Messages postés
35
Date d'inscription
samedi 26 février 2005
Statut
Membre
Dernière intervention
12 août 2006

Comment faire pour que mon serveur sache differencier un envoi de données (par exemple un message) et une connection.

Tel que mon programme est construit, lorsqu'un client se connecte ou lorsque qu'il envoi un message, je passe par Ecoute()

Je ne veux pas creer un nouveau Socket à chaque fois qu'un client envoi un message.
Suis un peu paumé :)
Messages postés
35
Date d'inscription
samedi 26 février 2005
Statut
Membre
Dernière intervention
12 août 2006

Je reposte ma nouvelle fonction Ecoute()

public void Ecoute()
{
    //ajout du nouveau socket dans la liste
    this.ListSocket.Add(socket_ecoute.AcceptSocket());

    //creation d'un socket temporaire pour les traitements
    Socket MySocket = (Socket)this.ListSocket[this.ListSocket.Count-1];
               

    while(stop)
    {
            Console.WriteLine("Ecoute()");
            Byte[] buffer = new Byte[1024];
            MySocket.Receive(buffer);
            string data = Encoding.ASCII.GetString(buffer).TrimEnd('\0');

            // On envoi le texte aux clients
            if (data != "")
           {
                            Console.WriteLine(data);
                            for (int i = 0; i < this.socketJoueurs.Count; i++)
                            {
                                EnvoieAuClient((Socket)this.ListSocket[i], data);
                            }
             }                  
    }
}

Ca ne marche toujours pas avec deux clients :/
Messages postés
3466
Date d'inscription
lundi 16 octobre 2000
Statut
Modérateur
Dernière intervention
30 octobre 2008
46
Tu as lancé ecoute dans un autre Thread() ?

Mx
MVP C# 
Messages postés
35
Date d'inscription
samedi 26 février 2005
Statut
Membre
Dernière intervention
12 août 2006

Je n'ai pas changé les premieres lignes de me code.

Je n'ai toujours qu'un seul Thread :

// Creation d'une thread au chargement associé a la fontion Ecoute()
th = new Thread(new ThreadStart(Ecoute));
th.Start() ;

Je ne vois pas la difference entre les deux Threads dont tu me parles.
Il y aurait un Thread pour Ecoute() mais le deuxième ?
Messages postés
3466
Date d'inscription
lundi 16 octobre 2000
Statut
Modérateur
Dernière intervention
30 octobre 2008
46
Sépare l'acceptation des clients (là ou se trouve ton AcceptSocket()), et la communication avec eux.
2 méthodes, qui tournent dans 2 threads différents.

Relis mon premier message.
Fais, comme je t'ai montré. Une méthode qui accepte les clients, fais-en ta méthode Ecoute(), fais la tourner dans un thread.

Fais une autre méthode, qui fait tes socket.Receive(), etc. Et fais la tourner dans un autre Thread.

Sinon, je pourrais aussi te parler de l'ecoute asynchrone, la reception asynchrone, et l'envoi asynchrone, mais j'ai pas envie de t'embrouiller plus... ^^

Mx
MVP C# 
Messages postés
35
Date d'inscription
samedi 26 février 2005
Statut
Membre
Dernière intervention
12 août 2006

Est-ce que je dois faire autant de socket.Receive() que j'ai de sockets?

Par exemple

for (int i=0;i<this.listSocket.Count;i++) {
    Socket socketTemp=(Socket)this.listSocket[i];
    socketTemp.Receive(buffer);
}
Messages postés
3466
Date d'inscription
lundi 16 octobre 2000
Statut
Modérateur
Dernière intervention
30 octobre 2008
46
Chaque socket correspond a un client, donc il faut ecouter les messages de chaque client ;)

Mx
MVP C# 
Messages postés
3466
Date d'inscription
lundi 16 octobre 2000
Statut
Modérateur
Dernière intervention
30 octobre 2008
46
Tiens,

tu peux t'inspirer de ca pour comprendre

Mx
MVP C# 
Messages postés
35
Date d'inscription
samedi 26 février 2005
Statut
Membre
Dernière intervention
12 août 2006

Snif j'ai vraiment du mal aujourd'hui :D

J'ai donc fait mes deux Thread, un pour la connection des nouveaux clients

public void connecte() {
            this.socketJoueurs.Add(socket_ecoute.AcceptSocket());
}

Et un autre chargé de la reception et de l'emission des messages clients

for (int i = 0; i < this.socketJoueurs.Count; i++)                        {

                     //reception du message d'un client
                     Byte[] buffer = new Byte[1024];
                     Socket MySocket = (Socket)this.socketJoueurs[i];
                     MySocket.Receive(buffer);

                     string data = Encoding.ASCII.GetString(buffer).TrimEnd('\0');

                     //diffusion du message vers tous les clients
                     if (data != "")
                    {
                                Console.WriteLine(data);
                                for (int j = 0; j < this.socketJoueurs.Count; j++)
                                {
                                          EnvoieAuClient((Socket)this.socketJoueurs[i], data);
                                }

                     }
}

Je deviens fou !
Messages postés
3466
Date d'inscription
lundi 16 octobre 2000
Statut
Modérateur
Dernière intervention
30 octobre 2008
46
Il faut que tu boucles avec un while() dans ta méthode connecte..
Sinon, tu n'auras qu'un seul client qui va se connecter....

Voila commence ca se passe :
- Tu lance ton Thread qui appele la méthode connecte()
- Ta fonction se bloque sur AcceptSocket().
- Un client se connecte, le socket est ajouté a ta liste.
 Et ensuite ? telle qu'elle est, ta méthode connecte (et donc ton thread) va se terminer.

Entoure ton AcceptSocket avec un while. De cette facon, dès qu'un client est connecté, son socket stocké, hop, il repart sur AcceptSocket, et est pres pour la connexion d'un nouveau client (et comme le socket du client precedent est stocké dans ta liste, il n'est pas perdu, ni remplacé par le nouveau).

Mx
MVP C# 
Messages postés
35
Date d'inscription
samedi 26 février 2005
Statut
Membre
Dernière intervention
12 août 2006

Donc j'ai une evolution
Mon deuxième client arrive enfin à envoyer des messages
Je vois bien dans ma console serveur ce que raconte mon deuxieme client

Par contre mes envois ne fonctionnent pas encore.
Je vais chercher encore un peu, je devrai trouver ce qui ne colle pas.

Merci pour ton aide !!
Messages postés
3466
Date d'inscription
lundi 16 octobre 2000
Statut
Modérateur
Dernière intervention
30 octobre 2008
46
Y'a pas de quoi.
Bon courage !

Mx
MVP C# 
Messages postés
35
Date d'inscription
samedi 26 février 2005
Statut
Membre
Dernière intervention
12 août 2006

J'aurai deux questions

Dois-je créer un Thread() pour ecouter chaque client ou est-il possible de faire tourner un seul Thread() qui prendrait en charge toutes les ecoutes clients.

J'ai remarqué que lorsque je faisais tourner deux clients sur la même machine ca marchait très mal (les messages s'envoient par alternance : concurrence?) alors que sur deux machines differente ca se passe bien. Je n'arrive pas à m'expliquer ce comportement.
Messages postés
36
Date d'inscription
lundi 4 septembre 2006
Statut
Membre
Dernière intervention
4 mai 2007

Salut!!

Je suis également en train de faire un chat client-serveur, mais en Windows Application et non en console (pas d'énormes changements) et j'ai eut à peu près les mêmes problèmes que toi.

Maintenant, mon serveur accepte tous les clients qui se connectent,
tous les clients peuvent recevoir les messages du serveur,
mais le serveur ne reçoit que les messsges du 1er client connecté.

Pourtant, ma fonction d'écoute (sur le serveur) est dans un Thread et utilise la fonction foreach() pour récupérre le flux de chaque clients stockés dans un ArrayList[].

PS: mes clients sont des objets constitués d'un nom, d'un TCPClient, et d'un NetworkStream;
Messages postés
10
Date d'inscription
mardi 17 juin 2008
Statut
Membre
Dernière intervention
8 juillet 2008

Salut,

je suis en train de faire un serveur avec plusieurs clients.
je developpe un serveur en console qui voit bien tous ces clients et recoit des message de chacun.
MAIS il ne peut pas ecrire a un en particulier, tous les client recoivent le meme message. C'est tres genant dans mon application.

Si quelqu'un a du code qui fonctionne un peu, je suis prenneur.

Merci a tous
a++