Erreur lors du test

cs_H0gS Messages postés 2 Date d'inscription mercredi 25 juin 2008 Statut Membre Dernière intervention 19 avril 2011 - 19 avril 2011 à 03:46
LUDINSKI Messages postés 441 Date d'inscription mardi 2 décembre 2003 Statut Membre Dernière intervention 22 mai 2012 - 19 avril 2011 à 08:21
Bonjour à vous tous,

J'essaie lentement, mais sûrement de créer un chat à l'aide des sockets en mode connecté (TCP). Comme vous le remarquerez, je suis débutant en programmation réseau. J'espère que vous pourrez trouver mon ou mes erreurs.

Mon projet est divisé en 2 classes : SocketTCP et Serveur.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.Net.Sockets;

namespace ExChat.Connexion
{
    public abstract class SocketTCP
    {
        private const int PORT_DEFAUT = 8000;


        /// <summary>
        /// Obtenir l'adresse IP.
        /// </summary>
        public IPAddress IP { get; set; }


        /// <summary>
        /// Obtenir le port.
        /// </summary>
        public int Port { get; set; }


        /// <summary>
        /// Obtenir le point de communication.
        /// </summary>
        public IPEndPoint Connexion { get; set; }


        /// <summary>
        /// Obtenir la socket principale.
        /// </summary>
        public Socket Socket { get; set; }


        /// <summary>
        /// Constructeur par défault.
        /// </summary>
        /// IP à rejoindre.


        public SocketTCP(IPAddress ip,
                         int port)
        {
            // Initialiser l'adresse IP et le port
            IP = ip;
            Port = port;

            // Initialiser le point de communication
            Connexion = new IPEndPoint(IP, Port);

            // Initialiser la Socket principale
            Socket = new Socket(AddressFamily.InterNetwork,
                                SocketType.Stream,
                                ProtocolType.Tcp);
        }


        /// <summary>
        /// Constructeur surchargé.
        /// </summary>
        public SocketTCP()
            : this(Dns.Resolve(Dns.GetHostName()).AddressList[0],
                   PORT_DEFAUT)
        { }
    }
}


using System;
using System.Collections.Generic;
using System.Net;
using System.Net.Sockets;
using System.Threading;

namespace ExChat.Connexion
{
    class Serveur : SocketTCP
    {
        // État du veilleur
        private bool EnEcoute;

        // Liste des clients connectés au serveur
        public List<Socket> Clients { get; set; }


        /// <summary>
        /// Constructeur par défaut.
        /// </summary>
        public Serveur()
        {
            // Créer une liste de clients connectés
            Clients = new List<Socket>();

            try {
                // Lier le Socket du serveur au point de communication
                Socket.Bind(Connexion);

                // Mettre le socket du serveur en mode écoute
                Socket.Listen(10);

                while (true) {

                    // Accepter la connection du client
                    Clients.Add(Socket.Accept());

                    // Tester l'activation du veilleur
                    if (!EnEcoute) {

                        // Activier le veilleur
                        EnEcoute = true;

                        // Écouter les les requêtes des client
                        (new Thread(new ThreadStart(Ecouter))).Start();

                        // Gérer les connexions des clients
                        (new Thread(new ThreadStart(GererClients))).Start();
                    }
                }
            }
            catch (SocketException e) {

                // Afficher le message d'erreur
                Console.WriteLine(e.Message);
            }
        }


        /// <summary>
        /// Veilleur : écoute les message des clients.
        /// </summary>
        private void Ecouter()
        {
            // Tant que le veilleur est activé
            while (EnEcoute) {

                // Filtrer la liste de client en ne gardant que les clients actifs
                Socket.Select(Clients, null, null, 100);

                // Pour chaque client ayant envoyé un message
                foreach (Socket client in Clients) {

                    // Créer un tableau de bits de la dimension du message
                    byte[] message = new byte[client.Available];

                    // Placer le message dans le tableau de bits
                    client.Receive(message);

                    // Afficher le message
                    Console.WriteLine(System.Text.Encoding.UTF8.GetString(message));
                }
            }
        }


        /// <summary>
        /// Gérer les clients connectés.
        /// </summary>
        private void GererClients()
        {
            // Tant que le veilleur est activé
            while (EnEcoute) {

                // Pour chaque client
                foreach (Socket client in Clients) {

                    // Tester la connexion
                    if (!client.Poll(10, SelectMode.SelectRead)) {

                        // Retirer le client
                        Clients.Remove(client);
                    }
                }

                // Tester le nombre de clients connectés
                if (Clients.Count == 0) {

                    //Désactiver le veilleur
                    EnEcoute = false;
                }
            }
        }
    }
}


Merci pour votre aide.
Hugo.

2 réponses

LUDINSKI Messages postés 441 Date d'inscription mardi 2 décembre 2003 Statut Membre Dernière intervention 22 mai 2012 8
19 avril 2011 à 08:01
Bonjour,

Déjà il ne va pas aimer les déconnexions :)
Tu ne peux pas modifier ta liste Clients dans le foreach
donc dans la méthode GererClient() il faudrait écrire un truc du genre :

// Parcourt les clients
int clientIndex = 0;
while( clientIndex < Clients.Count )
{
    Socket client = Clients[ clientIndex ];

    // Tester la connexion
    if (!client.Poll(10, SelectMode.SelectRead))
    {
        // Retirer le client
        Clients.Remove(client);
        continue;
    }

    // Passe au client suivant
    clientIndex++;
}
0
LUDINSKI Messages postés 441 Date d'inscription mardi 2 décembre 2003 Statut Membre Dernière intervention 22 mai 2012 8
19 avril 2011 à 08:21
Autre erreurs (x2) :

1) Il faut sécuriser l'accès à ta liste Clients puisqu'elle est utilisée dans différents Threads...

2) A chaque nouveau client tu lances deux thread qui gère tout les clients...
Donc soit tu ne lances les deux thread qu'une seule fois, soit tu fais en sorte que chaque thread ne gère qu'un des clients... (je sais pas si je suis clair :)

Bref, je te propose ceci pour ta classe Serveur :

class Serveur : SocketTCP
{
    // État du veilleur
    private bool EnEcoute;

    // Liste des clients connectés au serveur
    public List<Socket> Clients { get; set; }

    // Variable utilisé pour "locker" la liste Clients
    private string _lockClients = "Clients locker";

    /// <summary>Constructeur par défaut</summary>
    public Serveur()
    {
        // Créer une liste de clients connectés
        Clients = new List<Socket>();

        try
        {
            // Lier le Socket du serveur au point de communication
            Socket.Bind( Connexion );

            // Mettre le socket du serveur en mode écoute
            Socket.Listen( 10 );

            while( true )
            {
                // Accepter la connection du client
                Socket newClient = Socket.Accept();

                // Lock l'accès à "Clients"
                lock( _lockClients )
                {
                    // Ajoute le client
                    Clients.Add( newClient );
                }

                // Tester l'activation du veilleur
                if( !EnEcoute )
                {
                    // Activier le veilleur
                    EnEcoute = true;

                    // Écouter les requêtes des client
                    (new Thread( new ThreadStart( Ecouter ) )).Start();

                    // Gérer les connexions des clients
                    (new Thread( new ThreadStart( GererClients ) )).Start();
                }
            }
        }
        catch( SocketException e )
        {
            // Afficher le message d'erreur
            Console.WriteLine( e.Message );
        }
    }

    /// <summary>Veilleur : écoute les message des clients</summary>
    private void Ecouter()
    {
        // Tant que le veilleur est activé
        while( EnEcoute )
        {
            // Filtrer la liste de client en ne gardant que les clients actifs
            Socket.Select( Clients, null, null, 100 );

            // Lock l'accès à "Clients"
            lock( _lockClients )
            {
                // Pour chaque client ayant envoyé un message
                foreach( Socket client in Clients )
                {
                    // Créer un tableau de bits de la dimension du message
                    byte[] message = new byte[ client.Available ];

                    // Placer le message dans le tableau de bits
                    client.Receive( message );

                    // Afficher le message
                    string msg = Encoding.Unicode.GetString( message );
                    if( !string.IsNullOrEmpty( msg ) )
                        Console.WriteLine( msg );
                }
            }
        }
    }

    /// <summary>Gérer les clients connectés</summary>
    private void GererClients()
    {
        // Tant que le veilleur est activé
        while( EnEcoute )
        {
            // Lock l'accès à "Clients"
            lock( _lockClients )
            {
                // Parcourt les clients
                int clientIndex = 0;
                while( clientIndex < Clients.Count )
                {
                    Socket client = Clients[ clientIndex ];

                    // Tester la connexion
                    if( !client.Poll( 10, SelectMode.SelectRead ) )
                    {
                        // Retirer le client
                        Clients.Remove( client );
                        continue;
                    }

                    // Passe au client suivant
                    clientIndex++;
                }

                // Tester le nombre de clients connectés
                if( Clients.Count == 0 )
                {

                    //Désactiver le veilleur
                    EnEcoute = false;
                }
            }
        }
    }
}
0
Rejoignez-nous