Communication Socket-L2
Communication Socket-L2
Communication Socket-L2
Source : https://twitter.com/b0rk
1 Introduction
Lorsque l’on désire réaliser des applications client-serveur, il est nécessaire d’utiliser les Socket 1 et dans
votre domaine de prédilection, l’informatique, vous devez avoir quelques notions sur la programmation d’une
application client-serveur.
Dans ce chapitre, nous allons juste voir les grandes lignes et appréhender le développement d’une simple
application.
En effet, il existe une multitude de solutions selon que l’on désire créer un serveur itératif ou un serveur
parallèle en utilisant une communication en mode connecté ou non connecté.
Ce cours est loin d’être exhaustif et je vous invite à lire différents ouvrages à ce sujet, notamment celui de
Jean-Marie Rifflet : La communication sous UNIX, Applications réparties, dans lequel j’ai pioché quelques
exemples.
Il existe aussi une multitude sites Web que je trouve très intéressants tels :
Il existe de nombreux sites qui l’expliquent surement même mieux que moi.
Vous pourrez faire le TP en python ou un autre langage plus moderne, java par exemple ,si vous le voulez.
2 Rappels
Quelques rappels sur la notion client/serveur et le modèle en couche ?
1. La traduction littérale est : prise ou point de communication
— le serveur : C’est une machine sur laquelle un service est réalisé ou un processus (thread) qui rend ce
service ;
— le client : C’est une machine faisant appel à une machine serveur ou un processus sollicitant un processus
serveur.
Question : Quel est le seul protocole où il n’y a qu’un seul client et plein de serveurs ?
Réponse : SNMP : Simple Network Managment Protocol
C’est un protocole utilisé par les différents éléments actif d’un réseau (Ordinateurs, switchs, routeurs etc..)
sont interrogés régulièrement pas un client (le manager) pour connaitre leur état à chacun.
— Port de 49152 à 65535 est la zone d’attribution automatique des ports, pour la partie cliente des connexions
(si le protocole n’impose pas une valeur particulière) et pour les tests de serveurs locaux.
3 Les sockets
Mécanisme de communication permettant d’utiliser l’interface de transport TCP-UDP donc la couche 4 du
modèle OSI et s’appuyant sur IP.
Ce mécanisme fut introduit dans Unix dans les années 80, c’est un standard aujourd’hui !
3.1 Définition
Un (ou une...) socket est un point de contact dans une communication.
Elle permet à 2 entités, généralement un client et un serveur de se retrouver en relation et de pouvoir
communiquer, un peu comme les tubes que nous avons étudiés précédemment mais avec une puissance plus
conséquente.
Pour faire beaucoup plus simple, une socket est soit un téléphone, soit une boîte aux lettres...
ATTENTION : Je ne veux pas entendre qu’une socket c’est une IP et un N° de port, ce n’est pasque
ça ! ! ! et la couche 4 vous en faites quoi ?
Et puis des sockets il y en a plein sur une machine ! ! !
La preuve : la commande find -type s | wc -l sur ma VM me renvoie 44 donc 44 sockets
Voici le résultat, ceux qui sont soulignés doivent vus parler...
Voyons ce que sont celles qui sont dans /root/L3/TD_TP/socket juste par curiosité !
Un ls -l /root/L3/TD_TP/socket/local/socket_serveur
et un file /root/L3/TD_TP/socket/local/socket_serveur
renvoient
UN ou UNE SOCKET c’est donc un fichier sous Linux mais pas que ça ! ! ! !
— Points communs
— Le client a l’initiative de la communication ; le serveur doit être à l’écoute
— Le client doit connaitre la référence du serveur [adresse IP, n° de port]
il peut la trouver dans un annuaire si le serveur l’y a enregistrée au préalable, ou la connaître par
convention (/etc/services) : n°socket de port préafféctés
— Le serveur peut servir plusieurs clients (1 Processus/thread unique ou 1 Processus/thread par client)
Le code source dessous est celui d’une fonction permettant de créer et d’attacher une socket.
Quelques explications...
— La ligne 11 donne le type de structure utilisée pour l’adresse (voir plus loin).
— La ligne 17 crée la socket en utilisant la primitive socket.
— La ligne 25 attache la socket.
— Les lignes 21 à 23 permettent de remplir la structure contenant l’adresse.
— La ligne 27 montre la fermeture du fichier descripteur
— La ligne 30 permet d’obtenir le nom de la socket.
— La ligne 31 donne en retour la valeur du descripteur de fichier avec lequel nous aurons accès à la socket.
3. Et pour faire une droite, il faut 2 points...
Une socket est identifiée localement dans un processus par un descripteur, cette identification n’est valable
que dans le contexte du processus ! ! !
Comme le montre le programme suivant !
1 =
/ / programme 3 sockets . c
#include <stdio . h>
#include <s t d l i b . h>
#include <unistd . h>
#include <sys / types . h>
6 #include <sys / socket . h>
#include <netinet / in . h>
#include <arpa / inet . h>
int main ( ) {
11
int sockfd_serveur_TCP , sockfd_serveur_UDP ; / / descripteurs pour les 2 sockets
int sockfd_serveur_RAW ;
Si on désire que d’autres processus (sans lien de parenté) transmettent des données à destination
de la socket , il est nécessaire que ceux-ci disposent d’un moyen externe de nommer cette socket .
Le domaine d’une socket définit le format des adresses possibles, les sockets avec lesquelles elle
pourra communiquer, ainsi qu’une famille de protocoles utilisables.
Quelques domaines :
3.4.2 Le type d’une socket : détermine la sémantique des communications qu’elle permet de réaliser.
— SOCK_RAW : socket orientée vers l’échange de data-grammes à un niveau bas de protocole (IP par
exemple).
Elle est notamment utilisée par la commande ping... Ce mode n’est accessible qu’au super-utilisateur.
— SOCK_DGRAM : socket orientée vers la transmission de data-grammes structurées en mode non-connecté
avec une fiabilité minimale : UDP
— SOCK_STREAM : socket orientée vers l’échange de séquences continues de caractères, en mode connecté
avec garantie du maximum de fiabilité : TCP.
3.4.3 Le protocole d’une socket : L’argument protocole dans l’appel système socket est généralement mis à
0. Dans certaines applications spécifiques, il faut cependant spécifier la valeur du protocole.
AF_UNIX
Une socket est désignée dans le domaine UNIX comme un fichier, elle a un i-nœud.
Une telle adresse correspond à la structure suivante :
#include <sys/un.h>
struct sockaddr_un {
short sun_family ; /* AF_UNIX */
char sun_path[108] ; /*reference */
};
L’attachement d’une socket est faite seulement si la référence n’existe pas encore.
Cette référence peut être supprimée soit à l’aide de la commande externe rm ou bien dans le programme
avec la primitive unlink .
AF_INET
Une socket est désignée dans le domaine INET non pas comme un fichier, mais possède une adresse construite
en utilisant les structures suivantes :
Une telle adresse correspond à la structure suivante :
#include <netinet/in.h>
— Le champ sin_addr.s_addr peut avoir la valeur INADDR_ANY permettant ainsi d’associer la socket à
toutes les adresses possibles de la machine.
— Le champ sin_port peut avoir une valeur particulière, afin de permettre au client d’avoir accès à un
service particulier. (Voir le fichier /etc/services).
Remarque : si un processus crée un socket et commence à émettre sans un attachement de cette socket, le
système fera un attachement sur un port quelconque généralement compris entre 49152 et 65535 ! ! !
4 La communication en local
Les sockets sont principalement utilisées dans le domaine des réseaux afin de permettre à un serveur et
un client se trouvant sur 2 machines distinctes de communiquer. On peut néanmoins les utiliser pour faire
communiquer 2 processus en local.
On utilise pour cela les sockets dans le domaine local : AF_UNIX. Cela va nous permettre de voir rapidement
le fonctionnement et les mécanismes mis en jeu et nous aurons l’occasion de voir cela plus en détails lors du TP.
De son côté, il crée la socket (socket), l’attache (bind), prévient le système auquel il appartient qu’il est prêt
à accepter les demandes de connexion des clients (listen). Il se met en attente de demande de connexion.
Il dispose d’une socket d’écoute attachée au port correspondant au service et supposé connu des clients.
Lorsqu’une demande de connexion arrive, le système crée une nouvelle socket dédiée à cette nouvelle connexion
que l’on nomme socket de service, ce qui permet de multiplexer sur la même socket plusieurs connexions.
Le processus serveur prend connaissance de l’existence d’une nouvelle connexion par un appel à la primitive
accept : au retour de cet appel, le processus reçoit un descripteur lui permettant d’accéder à cette socket de
service.
Après avoir accepté une connexion le serveur qui est le père crée un fils (fork ) ou une activité (pthread _create)
et le dialogue se fait alors entre le fils et un client. Cela permet au serveur de pouvoir prendre plus rapidement
en compte les nouvelles demandes de connexion. C’est ce mécanisme qui est utilisé lorsque vous êtes plusieurs
à vouloir vous connecter simultanément sur un serveur Web, FTP, telnet etc...
Une connexion TCP est identifiée par un 4-uple :
5.1.2 Le client : est l’entité active 4 dans le processus d’établissement d’une connexion avec un serveur
C’est lui qui prend l’initiative. Cette demande de connexion est réalisée à l’aide de la primitive connect. Il
n’est pas nécessaire, pour appeler la primitive connect, que la socket locale ait été au préalable attachée à une
adresse : si un appel à la primitive bind n’a pas été fait avant la demande de connexion, un attachement sur un
port quelconque sera automatiquement réalisé à l’appel de la primitive connect.
L’image qui suit donne le déroulement d’une communication entre un serveur itératif TCP et un client TCP,
ainsi que la communication entre un serveur parallèle TCP et un client TCP.
Côté serveur
1. Création de la socket serveur
2. Récupération de l’adresse IP et du numéro de port du serveur donc le lien de la socket à l’adresse du
serveur
3. Mise en mode passif de la socket : elle est prête à accepter les requêtes des clients
4. (opération bloquante) : acceptation d’une connexion d’un client et création d’une socket service client,
dont l’identité est rendue en retour
4. Un peu comme les étudiants qui sont actifs et le prof qui est passif et attend leurs questions afin d’y répondre :)
5. Lecture,
traitement et
6. Écriture (selon algorithme du service)
7. Fermeture de la socket et remise en attente
Côté client
1. Création de la socket
2. Connexion de la socket au serveur
(a) choix d’un port libre pour la socket par la couche TCP
(b) attachement automatique de la socket à l’adresse (IP machine locale + n° de port)
(c) connexion de la socket au serveur en passant en paramètre l’adresse IP et le n° de port du serveur
3. Écriture donc dialogue avec le serveur (selon algorithme du service)
traitement et
4. Lecture
5. Fermeture de la connexion avec le serveur
Attention, on rappelle que dans le domaine AF_INET, la communication s’appuie sur le protocole UDP.
Il n’y a donc pas de service permettant à l’émetteur de savoir si son message est arrivé à destination ou non.
De plus, si plusieurs messages sont envoyés au même destinataire, l’émetteur n’est pas assuré que ses mes-
sages seront délivrés dans le bon ordre.
L’image qui suit donne le déroulement d’une communication entre un serveur itératif UDP et un client UDP,
ainsi que la communication entre un serveur parallèle UDP et un client UDP.
Côté serveur
1. Création de la socket serveur
2. Récupération de l’adresse IP et du numéro de port du serveur donc le lien de la socket à l’adresse du
serveur
3. Réception d’une requête de client
4. Traitement de la requête ; préparation de la réponse
5. Réponse à la requête en utilisant la socket et l’adresse du client obtenues par recvfrom ; retour pour
attente d’une nouvelle requête
Côté client
1. Création de la socket avec l’association à une adresse locale [adresse IP + n° port] est faite automatique-
ment lors de l’envoi de la requête.
2. Envoi d’une requête au serveur en spécifiant son adresse dans l’appel
traitement et
3. Réception de la réponse à la requête
4. Fermeture de la socket
7 Les primitives
Dans cette partie nous allons voir comment utiliser les primitives de base pour programmer des applica-
tions réseau. Certaines de ces primitives sont utilisées pour les modes connecté et non connecté, d’autres ne
fonctionnent qu’avec le mode connecté et bien sûr d’autres que pour le mode non connecté.
Il faudra donc bien faire attention lors de la programmation d’un client et/ou un serveur selon qu’il soit
destiné au mode oui/non connecté.
Remarque : Tout n’est pas expliqué, si vous voulez une documentation plus exhaustive, je vous autorise à
aller consulter les man :)
8 Conclusion
Ce n’est qu’un début... et les exemples sont en langage C, si vous voulez programmer une application dans
d’autres langages, à quelques exceptions prêt vous n’aurez qu’à faire du transcodage...
Il faudra surtout veiller à respecter les consignes données dans le déroulement d’une communication entre
un serveur et un client ou plusieurs clients en fonction des protocoles etc...
Exemple en python !
==
# * coding : utf 8 = =*=
# Le serveur . py
3 import socket
hote = ’ ’
port = 1664
print ( )
print ( )
13 print ( " Le serveur écoute à présent sur le port {}" . format( port ) )
print ( " Je vous sert quoi : ) ? " )
print ( )
print ( )
==
# * coding : utf 8 = =*=
# Le c l i e n t . py
3 import socket
Cela donne
et