Communication TCP avec TcpClient et TcpListener

Date de publication : 3/11/2008 , Date de mise à jour : 3/11/2008

Par Sabri Koffler (Accueil) (Blog)
 

Les classes TcpClient et TcpListener de .net 2.0 offrent une technique de programmation pratique de communication TCP

INTRODUCTION
I. La classe TcpClient
I-A. Construire un objet TcpClient
I-B. Obtenir un objet NetworkStream
I-B-1. Remarque sur la notion client et serveur
I-B-2. L'objet NetworkStream( System.Net.Sockets)
I-C. La méthode Write du NetworkStream
I-D. La méthode Read du NetworkStream
I-D-1. Définition : synchrone
II. La classe TcpListener
II-A. Création de l'objet TcpListener
II-B. Le démarrage de l'écoute
II-C. L'arrêt de l'écoute
III. Source d'exemple
IV. CONCLUSION
. Remerciements


INTRODUCTION

Le .net framework 2.0 fournit une manière de communication directe en TCP, sans forcément passer par des sockets. C'est une méthode un peu moins bas niveau que les sockets, mais qui reste un équivalent. Il s'agit des classes TcpClient et TcpListener. Elles peuvent être remplacées chacune par la classe Socket( System.Net.Sockets), et utilisées en même temps( par exemple un TcpListener et une Socket en client, ou bien une Socket en écouteur et un TcpClient en client).


I. La classe TcpClient

   Comme l'explique clairement MSDN, la classe TcpClient(System.Net.Sockets, dll : System) nous procure une manière de se connecter à un écouteur. Elle permet aussi de recevoir un flux de données et d'en émettre un à un écouteur, tout ceci se faisant en mode synchrone bloquant. Remarque : l'espace de nom, System.Net.Sockets, nous montre qu'il s'agit bien de l'équivalent des sockets, mais avec un enrobage objet plus sympathique, et qui paraît moins bas niveau. Un écouteur est un processus qui écoute les demandes de connexion entrantes (entrantes car on cherche à se connecter au serveur, donc sens client->serveur). On peut créer un écouteur notamment avec la classe TcpListener, que nous verrons bientôt, mais aussi avec la classe Socket (System.Net.Sockets) (ce qui prouve d'ailleurs que TcpClient équivaut aux sockets !).


I-A. Construire un objet TcpClient

Constructeur intéressant :

TcpClient monClientTcp = new TcpClient(nomServeur, port);
nomServeur est le nom DNS de l'ordinateur (le nom en toutes lettres que vous lui avez donné), mais cela peut être aussi son adresse IP.

Le numéro de port est le numéro de port de l'ordinateur hôte.

Ce constructeur essaye de se connecter dès que vous l'utilisez.

Pour que la connexion puisse s'établir, il faut, bien entendu, qu'un objet TcpListener soit à l'écoute, ou encore un objet de la classe Socket(System.Net.Sockets).

Fermeture : monClientTcp.Close( ) ;

Exceptions intéressantes pouvant être déclenchées:

(System.Net.Sockets.).SocketException


I-B. Obtenir un objet NetworkStream

   Une fois la connexion établie, vous avez besoin d'un objet de la classe NetworkStream pour pouvoir émettre ou recevoir des données.


I-B-1. Remarque sur la notion client et serveur

   Attention, les termes client/serveur ne signifient pas que le client ne peut pas émettre, ou que le serveur ne peut pas recevoir. Le client, comme le serveur, peut émettre ET recevoir des données. La seule différence entre les deux, c'est que l'écouteur( le serveur) est toujours en attente d'une demande de connexion d'un client. Donc ce processus écouteur est toujours actif. Alors que le client peut avoir une vie limitée : il se connecte quand il veut, et s'arrête quand il le souhaite. Par conséquent, la notion de serveur et de client existe essentiellement par rapport à la notion de connexion , et pas par rapport à la capacité d'émettre ou de recevoir des données. Ne croyez donc pas qu'un serveur ne peut qu'émettre des données, et qu'un client ne peut qu'en recevoir.

   Pour ces raisons, je ne préfère pas utiliser des termes comme " émetteur " pour désigner un TcpListener, ni utiliser " récepteur " pour désigner un TcpClient. Je préfère appeler client Tcp un objet TcpCLient, et serveur Tcp ( ou écouteur Tcp), un objet TcpListener.


I-B-2. L'objet NetworkStream( System.Net.Sockets)

L'objet NetworkStream représente le concept de flux de données circulant sur le réseau. Pour envoyer ou recevoir des données depuis votre objet TcpClient, vous devez disposer d'un objet NetworkStream. Ce qui semble intuitif ! Une fois cet objet obtenu, il suffira d'appeler sa méthode de lecture( méthode Read) ou d'écriture(méthode Write).

Pour obtenir un objet NetworkStream associé à votre objet TcpClient, utilisez la méthode GetStream de votre TcpClient.

NetworkStream monFlux = monClientTcp.GetStream();
Fermeture :

 monFlux.Close( )

I-C. La méthode Write du NetworkStream

La méthode Write permet d'envoyer des données. La syntaxe est la suivante :

byte[] monWriteBuffer;
  
monFlux.Write(monWriteBuffer, 0/* offset dans le buffer*/,
monWriteBuffer.Length);
Le premier paramètre est un tableau d'octets contenant les données à envoyer.

Le deuxième paramètre est l'offset dans ce tableau d'octets, à partir duquel commencent les données à envoyer. Cela revient à dire que c'est l'indice de début des données à transmettre. Par exemple, avec un offset = 2, les données transmises seront les données à partir de monWriteBuffer[2]. Ici nous mettons un offset à 0, c'est le cas le plus classique.

Le troisième paramètre est la taille des données à transmettre.

Exceptions intéressantes pouvant être déclenchées :

(System.IO).IOException, ObjectDisposedException

Dans le cas où nous devons envoyer une string, qui est un message classique, la démarche est la suivante :

- Convertir la string en ASCII( l'ASCII n'est plus utilisé, donc la string n'est en général pas directement en ASCII).

- Obtenir le résultat de cet conversion dans un tableau d'octets( byte[ ])

Une méthode faisant tout ce travail existe déjà. Il s'agit de la méthode GetBytes de l'attribut statique ASCII( qui est un objet) de la classe Encoding. Cette dernière fait partie de l'espace de noms System.Encoding .

Autrement dit :

string monMessage;
  
            /* Convertit la string en ASCII, et met le résultat dans un tableau d'octet */
monWriteBuffer = System.Text.Encoding.ASCII.GetBytes(monMessage.Text);

I-D. La méthode Read du NetworkStream

La méthode Read est semblable à la méthode write. Le premier paramètre est le tableau d'octets qui contiendra les données reçues. Le deuxième paramètre est toujours l'offset. Le troisième paramètre est le nombre d'octets à lire.

int nbLus = monFlux.Read(monReadBuffer, 0/*offset*/, monReadBuffer.Length);
                    //read peut déclencher exception
                    messageRecu =
                        System.Text.Encoding.ASCII.GetString(monReadBuffer, 0, nbLus/*tout le buffer n'est pas utilisé*/);
                    Console.WriteLine("Nb d'octet recus: ", nbLus);
Exceptions intéressantes pouvant être déclenchées :

(System.IO).IOException, ObjectDisposedExeption, ArgumentOutOfRangeException


I-D-1. Définition : synchrone

La méthode Read est synchrone, c'est-à-dire qu'elle va attendre de lire le nombre d'octets voulus, pour se terminer : elle est bloquante. Il y a donc une synchronisation entre celui qui a émis, et le déroulement du programme client, qui va se bloquer jusqu'à ce que les deux programmes soit synchronisés.


II. La classe TcpListener

La classe TcpListener permet d'obtenir un écouteur de connexion TCP. Les demandes de connexion peuvent provenir de la classe TcpClient vue ci-dessus, ou de la classe Socket. Ce qui prouve, une fois de plus, que les classes TcpClient et Socket sont, en réalité, équivalentes, et peuvent s'utiliser ensembles.


II-A. Création de l'objet TcpListener


private string strIPhote="127.0.0.1";
IPhote = IPAddress.Parse(strIPhote); //conversion
monListenTcp = new TcpListener(IPhote, port); //le new ne déclenche pas d'exception
Le constructeur demande un objet de la classe IPAddress( System.Net), qu'il est aisé d'obtenir à partir d'une string, grâce à la méthode statique Parse, de la classe IPAddress. Le numéro de port est le numéro de port de l'ordinateur hôte.

Exceptions intéressantes pouvant être déclenchées par ce constructeur:

Aucune


II-B. Le démarrage de l'écoute

Le démarrage de l'écoute se fait par l'appel de la méthode start de votre objet TcpListener.

monListenTcp.Start(); //début de l'écoute des demandes de connexion   
Exceptions intéressantes pouvant être déclenchées :

Uniquement (System.Net.Sockets.).SocketException

Une fois la méthode start appelée, il est nécessaire d'appeler une autre méthode : AcceptTcpClient, qui est bloquante. On en sort uniquement une fois qu'une connexion a été établie.

  //Le AcceptTcpClient est bloquant: notre programme se bloque jusqu'à
            //ce que quelqu'un demande à se connecter
            monTcpClient = monListenTcp.AcceptTcpClient();
On récupère un objet qui représente notre TcpClient qui vient de se connecter. Cet objet va être très pratique, car il va nous permettre d'exprimer ce qu'on veut effectuer par rapport à notre client( recevoir des données, en émettre, etc). Et, de plus, il va s'utiliser de la même manière que n'importe quel TcpClient : obtention d'un NetWorkStream par GetStream, appel des méthodes Read quand on veut lire des données envoyées par le client, et Write quand on veut envoyer des données au client, etc...


II-C. L'arrêt de l'écoute

La fermeture de l'écouteur se fait par un appel de la méthode stop de notre TcpListener.

  monListenTcp.Stop();
Exceptions intéressantes pouvant être déclenchées :

Uniquement (System.Net.Sockets.).SocketException


III. Source d'exemple

Voici un source que j'ai écrit pour vous aider à comprendre. Par la même occasion, vous y trouverez un exemple d'utilisation de thread( cas simple, aucune synchronisation, mais besoin réel d'un thread).

Code source téléchargeable ici (miroir)


IV. CONCLUSION

Les classes réseau TcpClient et TcpListener sont intéressantes car elles donnent le moyen d'accéder aux sockets, tout en gardant un esprit objet. On peut ainsi réaliser agréablement et joliment une communication TCP. Leur utilisation est assez facile.


. Remerciements

Merci à Amel Koffler pour la relecture, à Louis-Guillaume Morand et Jérôme Lambert, pour leur soutien et aide, ainsi qu'à toute l'équipe de Developpez.com .



Valid XHTML 1.1!Valid CSS!

Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par les droits d'auteur. Copyright © . Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts. Droits de diffusion permanents accordés à Developpez LLC. Cette page est déposée.

 
 
 
 
Partenaires

Hébergement Web