Les Sockets ou comment communiquer sur internet …
Je vais essayer de vous montrer comment utiliser les sokets dans un projet. Je ne vais pas le faire dans un “projet vide” directement mais plutôt mais dans une classe que nous pourrons réutiliser.
Mise en place d’un projet vierge
(Regardez sur le site l’article correspondant)
Ceci fait, on passe à la suite…
Ajout d’une classe vierge
Par le biais du menu “Fichier” faites “ajouter nouvel élément” puis classe. Nomez la et vous êtes prés.
Ce qu’a besoin une connection
Bon, réfléchissons sur ce qu’a besoin une connection … Voyons voir … Ha oui, un Socket. Allez donc voir sa définition dans un article du site.
Voyez donc que certains paramètres sont complexes. Nous allons donc développer un exemple pour plus de facilité.
Exemple
Un petit exemple sympa : un client web … Non, non, ça ne sera pas un firefox like car on va juste le faire en mode texte, juste pour tester les sockets.
La classe vide
Revenons à notre classe de faite. En voici le code (une fois la classe renommée)
//J'ai supprimé les commentaires pour plus de lisibilité. using System; //Le using utile pours les sockets using System.Net.Sockets; using System.Net; namespace ClientWeb { public class Connection { public Connection() { } } }
Dans notre exemple il nous faudra en private :
- un Socket
- un bool pour savoir si tout c’est bien passé
- une string pour connaitre la dernière erreur
ce qui nous donne :
using System; using System.Net.Sockets; using System.Net; namespace ClientWeb { public class Connection { Socket mainSocket; bool Error; string LastError; public Connection() { } } }
un nouveau constructeur
La fonction “public Connection()” est le constructeur par défaut, je dois avouer que celui ci ne sert à rien sous cette forme car notre classe sera utilisée pour la connection à un serveur, sur un port déterminé.
Transformons alors ce constructeur :
public Connection(string serveur, int port) { Error = false; mainSocket = new Socket(AddressFamily.InterNetwork,SocketType.Stream,ProtocolType.Tcp); try { System.Net.IPHostEntry IPHE = System.Net.Dns.GetHostByName(serveur); if(IPHE.AddressList.Length < 1) { Error = true; LastError = "Hote existant mais impossible de trouver une adresse"; return; } System.Net.IPEndPoint IPEP = new System.Net.IPEndPoint(IPHE.AddressList[0],port); mainSocket.Connect(IPEP); } catch { Error = true; LastError = "Impossible de trouver l'hote"; return; } }
Explications :
- mainSocket est initialisé de telle manière qu’il accepte le TCP.
- IPHE est l’élément qui contiendra l’analyse de l’adresse du serveur
- System.Net.Dns.GetHostByName() permet de déterminer les adresses d’un host par son nom
- Le try catch est pour prévenir l’erreur de getHostByName due à un hote introuvable
- IPEP est l’endroit de destination de notre connection avec une adresse et un port
- Et enfin la connection principale : mainSocket.Connect(IPEP);
Pour tester notre classe il nous faut écrire :
Connection c = new connection(google.fr,80); mais attention, ceci ouvre une connection qu’il serait bon de refermer …
Fermeture de connection
On ajoute alors dans notre classe :
public void CloseConnection() { if(mainSocket != null) if(mainSocket.Connected) mainSocket.Close(); }
Si mainSocket est initialisé et que mainSocket est connecté, on le ferme.
Envoie réception de donnée
Passons à l’envoie et la réception de donnée. Il nous faut bien communiquer avec ce socket ouvert non ? L’envoie est un jeu d’enfant alors que la réception reste un peu plus dure…
Sachez que mainSocket.Send() et mainSocket.Receive() n’acceptent que des bytes …
La réception ressemble à ceci :
public void Envoie(string str) { if(mainSocket == null) return; if(!(mainSocket.Connected)) return; //GetBytes transforme une string en tableau de bytes. mainSocket.Send(System.Text.Encoding.Default.GetBytes(str)); }
Mais il vous faut ajouter ceci dans les “usings” :
using System.Text;
Quant à notre problème de lecture, voici la solution :
public string Recoie() { if(mainSocket == null) return ""; if(!(mainSocket.Connected)) return ""; int MAXBUFFER = 200; int Octet_Lu = 1; byte[] first_buffer = new byte[MAXBUFFER]; string LastReadString = ""; while(Octet_Lu != 0) { Octet_Lu = mainSocket.Receive(first_buffer,0,MAXBUFFER,System.Net.Sockets.SocketFlags.None); if( Octet_Lu != 0) LastReadString += System.Text.ASCIIEncoding.Default.GetString(first_buffer,0,Octet_Lu); } return LastReadString; }
Notre algorithme fait ceci :
Tant que je ne lit pas ” à vide” je continu à lire MAXBUFFER octets et je les écrits.
Dans un autre cas, nous aurions pu changer d’algorithme si nous avions connu la longueur du paquet ou bien sa fin, etc …
Utilisation finale
Notre classe connection est finie …
Voici son utilisation :
Connection C = new Connection("Ogame.fr",80); C.Envoie("GET / HTTP 1.1\r\n\r\n"); string reponse = C.Recoie(); C.CloseConnection();
Et, ho miracle, si vous affichez reponse, vous voyez le code HTML de la page de ogame.fr …
Ceci conclue mon premier tutorial de niveau intermédiaire sur les sockets. Pour vous faire rager un peu, je vous invite a regarder la classe TcpClient et HTTPrequest (si je me rapelle bien) et vous verrez que leur utilisation est peu être un peu plus simple. Pour ma part, j’utiliserais la classe Socket pour toutes mes connections.