L'objectif de développement étant l'initiation, on se limite à un code minimaliste utilisant deux programmes distincts : un serveur et un client. Ces deux programmes échangent des chaînes caractères. Le «client» émet un message que le «serveur» traite et retransmet vers le «client». Le traitement est tout aussi minimaliste. Il s'agit de convertir la chaîne de caractères en majuscules.
Le schéma ci-dessous positionne les couches de la modélisation des communications réseau vis-à-vis du système d'exploitation.
Les pilotes de périphériques et les protocoles implantés depuis la couche physique jusqu'à la couche transport font partie du sous-système réseau du noyau du système d'exploitation.
Le programme utilisateur est lancé à partir de la couche Shell et est exécuté au niveau application.
L'utilisation de socket revient à ouvrir un canal de communication entre la couche application et la couche transport. La programmation des sockets se fait à l'aide de bibliothèques standard présentées ci-après : Section 2.4, « Bibliothèques utilisées ».
Il est possible de compiler ces deux programmes en l'état sur n'importe
quel système GNU/Linux. Il suffit d'appeler le compilateur C++ de la chaîne
de développement GNU en désignant le nom du programme
exécutable avec l'option -o.
$ g++ -o udp-client udp-client.cc $ g++ -o udp-server udp-server.cc $ ls -l udp* -rwxr-xr-x 1 phil phil 12217 3 mars 16:29 udp-client -rw-r--r-- 1 phil phil 3853 3 mars 16:29 udp-client.cc -rwxr-xr-x 1 phil phil 11084 3 mars 16:30 udp-server -rw-r--r-- 1 phil phil 2744 3 mars 16:29 udp-server.cc
L'exécution du programme est aussi assez triviale. On peut exécuter le client et le serveur sur le même hôte dans deux Shells distincts et utiliser l'interface de boucle locale pour les communications réseau.
$ ./udp-server Entrez le numéro de port utilisé en écoute (entre 1500 et 65000) : 4000 Attente de requête sur le port 4000 Depuis 127.0.0.1:60471 Message reçu : texte du message
$ ./udp-client Entrez le nom du serveur ou sont adresse IP : 127.0.0.1 Entrez le numéro de port du serveur : 4000 Entrez quelques caractères au clavier. Le serveur les modfiera et les renverra. Pour sortir, entrez une ligne avec le caractère '.' uniquement Si une ligne dépasse 100 caractères, seuls les 100 premiers caractères seront utilisés. Saisie du message : texte du message Message traité : TEXTE DU MESSAGE Saisie du message : .
Les deux programmes utilisent les mêmes fonctions disponibles à partir des bibliothèques standards.
libc6-dev,
netdb.h
Opérations sur les bases de données réseau. Ici, c'est la fonction
gethostbyname() qui est utilisée. Elle renvoie une
structure de type hostent pour l'hôte
name. La chaîne name est
soit un nom d'hôte, soit une adresse IPv4 en notation
pointée standard, soit une adresse IPv6 avec la
notation points-virgules et points. Pour obtenir plus d'informations, il
faut consulter les pages de manuels : man
gethostbyname.
libc6-dev,
netinet/in.h
Famille du protocole Internet. Ici, plusieurs fonctions sont
utilisées à partir du paramètre de description de socket
sockaddr_in. Les quatre fonctions importantes
traitent de la conversion des nombres représentés suivant l'hôte (octet
le moins significatif en premier sur processeur Intel x86) ou les
définitions des en-têtes réseau (octet le plus significatif en
premier).
htonl() et
htons() : conversion d'un entier long et d'un
entier court depuis la représentation hôte (octet le moins significatif
en premier ou Least Significant Byte First)
vers la représentation réseau standard (octet le plus significatif en
premier ou Most Significant Byte
First).
ntohl() et
ntohs() : fonctions opposées aux précédentes.
Conversion de la représentation réseau vers la représentation
hôte.
libstdc++6-dev,
iostream
Opérations sur les flux d'entrées/sorties de base tels que l'écran et le clavier. Ici, toutes les opérations de saisie de nom d'hôte, d'adresse IP, de numéro de port ou de texte sont gérées à l'aide des fonctions usuelles du langage C++. Ces fonctions sont les seules qui soient spécifiques au langage C++.
D'une manière générale, toutes les fonctions sont documentées à l'aide
des pages de manuels Unix classiques. Soit on entre directement à la console
une commande du type : man inet_ntoa, soit on
utilise l'aide du gestionnaire graphique pour accéder aux mêmes informations
en saisissant une URL du type suivant à partir du
gestionnaire de fichiers : man:/inet_ntoa.
Au dessus du protocole de couche réseau IP, on doit choisir entre deux protocoles de couche transport : TCP ou UDP.
Le protocole TCP est le premier protocole développé. Il «porte la moitié» de la philosophie du modèle Internet. Cette philosophie veut que la couche transport soit le lieu de la fiabilisation des communications. Ce protocole fonctionne donc en mode connecté et contient tout les outils nécessaires à l'établissement, au maintien et à la libération de connexion. De plus, des numéros de séquences garantissent l'intégrité de la transmission et le fenêtrage de ces numéros de séquences assure un contrôle de congestion. Tout ces mécanismes ne sont pas évidents à maîtriser pour un public débutant.
Le protocole UDP a été développé après TCP. La philosophie de ce mode de transport suppose que le réseau de communication est intrinsèquement fiable et qu'il n'est pas nécessaire de garantir l'intégrité des transmissions et de contrôler la congestion. On dit que le protocole UDP n'est pas orienté connexion ; ce qui a pour conséquence d'alléger considérablement les mécanismes de transport.
L'objectif du présent document étant d'initier à l'utilisation des sockets, on s'appuie sur le protocole de transport le plus simple : UDP. En termes de développement, les différences de mise en œuvre des sockets sont minimes. C'est à l'analyse réseau que la différence se fait. UDP est plus facile à utiliser avec un public débutant.
Pour plus d'informations, consulter le support Modélisations réseau.
Le schéma ci-dessous présente les sous-programmes sélectionnés côté client et côté serveur pour la mise en œuvre des sockets avec le protocole de transport UDP.
Les appels de sous-programmes avec les passages de paramètres sont détaillés dans les sections suivantes.
Vous êtes ici :