cs_H0gS
Messages postés2Date d'inscriptionmercredi 25 juin 2008StatutMembreDernière intervention19 avril 2011
-
19 avril 2011 à 03:46
LUDINSKI
Messages postés441Date d'inscriptionmardi 2 décembre 2003StatutMembreDernière intervention22 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;
}
}
}
}
}
LUDINSKI
Messages postés441Date d'inscriptionmardi 2 décembre 2003StatutMembreDernière intervention22 mai 20128 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++;
}
LUDINSKI
Messages postés441Date d'inscriptionmardi 2 décembre 2003StatutMembreDernière intervention22 mai 20128 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;
}
}
}
}
}