2. Sockets (prises)
2
Les sockets permettent la communication entre
processus situés
sur une même machine
ou sur des machines différentes
Socket est un point d'une communication :
envoi: un message est envoyé vers une socket
réception: un message est reçu sur une socket
Deux modes de communication
mode non connecté (sans connexion)
messages (ou datagrammes)
transport non fiable
mode connecté (avec connexion)
séquences de caractères (flot d’octets ou stream)
transport fiable
ordre FIFO
3. Insertion dans l’environnement
4
Pour chaque socket le système gère la structure de données
nécessaire à la communication (tampon + indices dans
tampon + …)
4. Désignation (ou nommage)
5
Désignation d'une socket:
Désignation (ou adresse) interne : indice dans la table des
descripteurs de fichiers du processus
Désignation (ou addresse) externe : adresse IP machine + numéro
de port
5. Place des sockets
7
Les sockets fournissent une
interface d’accès, à partir d’un
hôte, aux interfaces de transport
TCP et UDP
TCP (mode connecté) :
une liaison est établie au
préalable entre deux hôtes,
ensuite les messages (plus
exactement des flots d’octets)
sont échangés sur cette liaison
UDP (mode non connecté) :
aucune liaison n’est établie
Les messages sont échangés
individuellement
6. TCP vs UDP
8
TCP
Communication par flots
d’octets
Transmission fiable
Fiabilité garantie dès lors
que la liaison physique
existe
Transmission ordonnée
Ordre de réception
identique à l’ordre
d’émission
Contrôle de flux
Permet au récepteur de
limiter le débit d’émission en
fonction de ses capacités
UDP
Communication par
datagrammes
Transmission non fiable
il n'y a pas de garantie de
bonne livraison d'un
datagramme à sa
destination
Transmission non
ordonnée
l'ordre d'arrivée des
datagrammes peut différer
de l'ordre d'envoi
7. Principes de base
9
1. Chaque machine crée une socket,
2. Chaque socket sera associée à un port de sa
machine hôte,
3. Les deux sockets seront explicitement connectées
si on utilise un protocole en mode connecté …,
4. Chaque machine lit et/ou écrit dans sa socket,
5. Les données vont d’une socket à une autre à
travers le réseau,
6. Une fois terminé chaque machine ferme sa socket.
8. Définition des sockets
10
Familles de sockets :
processus sur la même station Unix :
sockets locales (AF_UNIX)
processus sur des stations différentes à travers Internet :
sockets Internet (AF_INET)
Modes de communication :
Datagrames – ou mode non connecté (SOCK_DGRAM)
Flôt de données – ou mode connecté (SOCK_STREAM)
Protocoles de sockets : IP, IPSec, AppleTalk,…
9. Format de présentation en mémoire
Ordre des bits
11
Les données ne sont pas représentées de la même
façon par tous les processeurs (host byte order ou
ordre des octets de l’hote)
Big Endian : bit de poids fort à gauche
Little Endian : bit de poids fort à droite
Expression des @ des machines et des numéros de
ports :
Une communication met en jeu 2 machines identifiées
par @machine et #port
Les deux machines peuvent avoir des codages
différents des nombres
Pour remédier à ce problème, le protocole IP définit un
standard, le network byte order (ordre des octets du
réseau) Big Endian
10. Conversion des nombres
12
htons() : host to network short (2 octets)
convertit un entier court (short) depuis l'ordre des
octets de l'hôte (Host byte order) vers celui du réseau
(Network byte order).
htonl() : host to network long (4 octets)
convertit un entier long depuis l'ordre des octets de
l'hôte vers celui du réseau
ntohs() : network to host short
convertit un entier court depuis l'ordre des octets du
réseau vers celui de l'hôte
ntohl() : network to host long
convertit un entier long depuis l'ordre des octets du
réseau vers celui de l'hôte
11. Conversion des @IP
13
in_addr inet_addr (const char *cp);
convertit l'adresse Internet de l'hôte cp depuis la notation
standard avec nombres et points en une donnée binaire dans
l'ordre des octets du réseau
si l'adresse est invalide, -1 est renvoyé
char * inet_ntoa (struct in_addr in);
convertit l'adresse Internet de l'hôte in donnée dans l'ordre des
octets du réseau en une chaîne de caractères dans la
notation avec nombres et points
Le numéro fictif INADDR_ANY signifie que la socket peut-
être associée à n'importe quelle adresse IP de la machine
locale (s'il en existe plusieurs).
12. La fonction gethostbyname
14
Utiliser les DNS (Domain Name Services) pour éviter la
manipulation des @IP (www.google.com 216.239.39.99)
La fonction gethostbyname renvoie une structure de données
(hostent) en interrogeant le serveur DNS avec le nom de l’hôte
(name)
struct hostent { char *h_name;
char **h_aliases;
int h_addrtype;
int h_length;
char **h_addr_list;
}
#define h_addr h_addr_list[0]
h_name : nom officiel de l'hôte
h_aliases : table d'alternatives au
nom officiel de l'hôte
h_addrtype : type d'adresse
(AF_INET)
h_length : longueur, en octets, de l’@
h_addr_list : table d’@ réseau pour
l'hôte, avec l'ordre des octets du
réseau
struct hostent * gethostbyname (const char *
name);
13. Programmation des sockets
15
Plusieurs langages possibles :
C, C++, Java, JavaScript, PHP, …
Plusieurs systèmes d’exploitation
Windows, Linux, MacOS,…
Dans la suite, on traite les sockets uniquement
en langage C avec le système d’exploitation
Linux
14. struct sockaddr {
unsigned short sa_family;
unsigned char sa_data[14];
};
Une structure générique qui permet d'utiliser n'importe quelle
couche réseau (IP, IPSec, AppleTalk,...)
sa_family : contient le type d’adresse : AF_INET ou AF_UNIX
sa_data : contient l’adresse de destination et le numéro de
port
Il existe également une autre structure faite pour contenir les
informations IP, c'est cette structure là que l'on va utiliser.
Adresse générique d’une socket
16
15. Adresse Internet d’une socket
17
sockaddr_in :
adresse Internet
Plus spécialisée que sockaddr
Même taille que sockaddr
sin_family :
AF_UNIX ou AF_INET
sin_port :
le numéro de port
sin_addr :
une structure de type addr_in qui servira à
contenir l'adresse IP destination
sin_zero :
une suite des zero
Nécessaire pour que la taille de la
structure sockaddr_in soit la même que
celle de sockaddr.
L’affectation des zeros doit être réalisée
avec la fonction memset()
struct in_addr {
unsigned long s_addr;
};
struct sockaddr_in {
unsigned short sin_family;
unsigned short sin_port;
struct in_addr sin_addr;
char sin_zero[8];
};
16. socket : définition de socket
18
Création d'une socket = allocation de la structure de
données:
int socket (int domaine, int type, int protocole)
domaine:
AF_UNIX : pour communication locale (même machine)
AF_INET : réseau internet
type:
SOCK_STREAM : mode connecté, communication fiable, TCP
SOCK_DGRAM : mode non connecté, communication non
fiable, UDP
protocole: la valeur 0 emploie le protocole par défaut selon
le type
l'appel retourne
un descripteur de socket ( = indice dans la table des descripteurs
de fichiers du processus)
17. bind : attribution d'une adresse
externe
19
Après sa création, une socket n'a pas d'adresse
externe;
une adresse externe est attribuée grâce à la fonction
bind
int bind (int sockfd, struct sockaddr * my_addr, int
addr_len)
sockfd: descripteur de socket
my_addr: pointeur sur une structure sockaddr qui
contient
adresse machine locale (adresse IP)
18. close : fermeture d’une socket
20
pour fermer la socket :
int close (int sockfd)
sockfd: descripteur de socket.
19. Communication en mode déconnecté
(UDP)
21
le serveur et le client ouvrent chacun une « socket »
le serveur la nomme (il l’attache à un de ses ports (un
port précis))
le client ne nomme pas sa socket (elle sera attachée
automatiquement à un port lors de l’émission)
le client et le serveur dialogue : sendto(…) et
recvfrom(…)
finalement toutes les sockets doivent être refermées
Les deux extrémités n’établissent pas une
connexion :
elles ne mettent pas en œuvre un protocole de maintien de
connexion
si le processus d’une extrémité meurt l’autre n’en sait rien !
20. Communication en mode déconnecté
(UDP)
22
socket() : création d’une
socket
bind() : attache la socket à une
adresse externe (@ et #Port)
sendto() : envoi d'un message
recvfrom() : réception du
message
close() : fermeture de la socket
22. sendto : envoi en mode datagrammes
(UDP)
24
int sendto ( int sockfd, void *buf, int long, int option,
struct sockaddr *dst, int lg_addr )
sockfd: descripteur de socket de l'émetteur;
buf: adresse du buffer contenant le message à
envoyer;
long: longueur du message à envoyer;
dst: adresse externe de la socket du destinataire
(machine, port);
si sockfd n'est pas lié à un port local (fonction bind),
ceci est fait automatiquement par l'appel sendto (le
numéro de port est choisi parmi les ports libres);
option 0 pour DGRAM
retourne le nombre d’octets effectivement envoyés
23. recvfrom : réception en mode datagrammes
(UDP)
25
int recvfrom (int sockfd, void * buf, int long, int
option,
struct sockaddr *exp, int * lg_addr)
sockfd: descripteur de socket du récepteur
buf: buffer pour stocker le message reçu
long: taille du buffer
exp: adresse externe de l'expéditeur (machine, port),
pour l'envoi d'une éventuelle réponse
l'appel retourne la longueur du message reçu
ne permet de recevoir qu’un seul message:
exactement un message est extrait du tampon de
réception. S’il est plus long que l’espace alloué par le
récepteur, il est tronqué et le reste du message est
perdu.
25. Création de
socket
Création de l’@
externe de socket
serveur
Réception de msg
Envoi de msg
Fermeture de
socket
Client UDP
(Squelette)
26. Communication en mode connecté
(TCP)31
2 phases:
établissement de la connexion,
puis communication
Echange bidirectionnel fiable de séquences d'octets
(ordre FIFO)
Une fois la connexion établie: P1 désigne pour
envoyer et recevoir; P2 désigne pour envoyer et
recevoir
27. Communication en mode connecté
(TCP)32
Etapes d’une connexion client-serveur en TCP :
le serveur et le client ouvrent chacun une « socket »
le serveur la nomme (il l’attache à un de ses ports (un port
précis))
le client n’est pas obligé de la nommer (elle sera attachée
automatiquement à un port lors de la connexion)
le serveur écoute sa socket nommée
le serveur attend des demandes de connexion
le client connecte sa socket au serveur et à un de ses ports (précis)
le serveur détecte la demande de connexion
une nouvelle socket est ouverte automatiquement
le serveur crée un processus pour dialoguer avec le client
le nouveau processus continue le dialogue sur la nouvelle socket
le serveur peut attendre en parallèle de nouvelles demandes de
connexions
finalement toutes les sockets doivent être refermées
28. Communication en mode connecté
(TCP)33
socket() : création d' une
socket
bind() : attache la socket à
une adresse externe (@ et
#Port)
listen() : écoute de
connexions
connect() : demande une
connexion
accept() : accepte la
connexion
send() : envoi de données
recv() : réception des
29. Communication en mode connecté
(TCP)34
Etapes d’une connexion client-serveur en
TCP :
30. Communication en mode connecté
(TCP)35
Etapes d’une connexion client-serveur en
TCP :
31. Communication en mode connecté
(TCP)36
Détection de fin de connexion:
Protocole de maintien de connexion
Si le processus d’une extrémité meurt l’autre en est
averti
Si le client meurt la nouvelle socket automatiquement
ouverte sur le serveur est détruite
32. TCP: établissement de la
connexion37
L'établissement de la connexion n'est pas symétrique
Protocole du client / Protocole du serveur
Serveur : se déclare prêt à accepter une connexion en
désignant 4
Client : demande une connexion en désignant 1 et 3
Cette demande provoque la création de la socket 5|6,
et connecte 1|2 avec 5|6
34. Client-serveur en mode
concurrent
Pour réaliser un serveur en mode concurrent
(pour servir plusieurs clients simultanément):
créer un nouveau processus pour servir chaque
demande de connexion
le programme principal du serveur ne faisant que la
boucle dʼattente sur les demandes de connexion
Le processus principal (appelé veilleur) attend
sur accept()
Lorsquʼil reçoit une demande de connexion, il crée
un processus fils (appelé exécutant) qui va
interagir avec le client
Le veilleur revient se mettre en attente sur
accept()
Plusieurs exécutants peuvent exister
39
37. TCP côté client: connect( )
42
Demande de connexion (par le client):
int connect (int sockfd, struct sockaddr *dst_addr,
int len);
sockfd: descripteur de la socket du client
dst_addr: pointeur sur la structure sockaddr qui
contient
adresse IP de la machine serveur;
numéro de port;
len: longueur de la structure dst_addr
l'appel retourne 0 en cas de succès, -1 en cas
38. TCP côté serveur: listen ( )
43
Ouverture du service:
int listen (int sock, int len)
sock: descripteur de socket
len: longueur maximale de la queue de demandes de
connexion
une fois cette limite atteinte, une nouvelle demande de
connexion d'un client échoue
l'appel retourne 0 en cas de succès, -1 en cas d'erreur
39. TCP côté serveur: accept ( )
44
Attente de demande de connexion:
int accept ( int sockfd, struct sockaddr *client_addr,
int *len);
sockfd: descripteur de socket
client_addr: pointeur sur une structure sockaddr qui
contiendra
adresse machine du client connecté (adresse IP)
numéro de port
len: longueur de la structure client_addr
l'appel retourne le descripteur de la socket créée, ou –1
en cas d'erreur
40. send/recv: envoi et reception en mode TCP
45
int send ( int sockfd, void *buf, int long, int option)
sockfd: descripteur de socket de l'émetteur;
buf: adresse du buffer contenant les données à
envoyer;
long: taille des données à envoyer;
int recv( int sockfd, void *buf, int long, int option)
sockfd: descripteur de socket de récepteur;
buf: adresse du buffer contenant les données à
recevoir;
long: taille des données à recevoir;
43. Serveur TCP (2/2)
Pour un serveur concurrent (ou parallèle): cette fonction
serait
lancée en tant que tâche disjointe (exécutant) pour chaque
client
Hinweis der Redaktion
Socket = point de destination d'une communication:
sur une même machine (domaine AF_UNIX)
ou sur des machines différentes (domaine AF_INET).
À supprimer
Contrôle de congestion
Permet d’agir sur le débit d’émission pour éviter la surcharge du réseau
Communication bidirectionnelle par flots d’octets
ne pas confondre contrôle de flux (entre récepteur et émetteur ) et contrôle de
congestion (entre réseau et émetteur)
UDP : Les fonctions assurant la retransmission et le ré-ordonnancement doivent être assurées par les protocoles de la couche supérieure si elles sont souhaitées.
Toutes les combinaisons ne sont pas possibles !!
UDP, TCP
Les deux machines peuvent avoir des OS différents, des processeurs différents, des codages différent des nombres
Selon le système/matériel, le codage binaire des nombres peut changer
Big Endian : bit de poid forts à gauche
Little Endian : bit de poid forts à droite
Pour éviter une mauvaise interprétation des nombres
On les code en « mode réseau » lorsqu'on les utilise dans les structures ou fonctions d'accès au réseau et sockets
4 opérations assurent la traduction « mode réseau / local »
faut passer par un convertisseur avant de les envoyer sur le réseau
Sur les i80x86:
l'ordre des octets de l'hôte est LSB (Least Significant Byte first or little endian), c'est à dire octet de poids faible en premier
alors que sur les réseaux l'ordre est MSB (Most Significant Byte first ou big endian), octet de poids fort en premier
Si l'adresse est invalide, INADDR_NONE (généralement -1) est renvoyé. Ceci est une interface obsolète pour la fonction inet_aton, décrite ci-dessus, car -1 est une adresse valide (255.255.255.255), et inet_aton utilise un renvoi d'erreur plus propre.
char * inet_ntoa (struct in_addr in);
convertit l'adresse Internet de l'hôte in donnée dans l'ordre des octets du réseau en une chaîne de caractères dans la notation avec nombres et points. La chaine est renvoyée dans un buffer alloué statiquement, qui est donc écrasé à chaque appel.
int inet_aton (const char *cp, struct in_addr *inp);
convertit l'adresse Internet de l'hôte cp depuis la notation standard avec nombres et points (format ASCII) en une donnée binaire, et la stocke dans la structure pointée par inp.
renvoie une valeur non nulle si l'adresse est valide, et zéro sinon.
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 stan dard, soit une adresse IPv6 avec la notation points-vir gules et points (Cf RFC 1884 pour la description des adresses IPv6). Si name est une adresse IPv4 ou IPv6, aucune recherche supplémentaire n'a lieu et gethostby name() copie simplement la chaine name dans le champ h_name et le champs équivalent struct in_addr dans le champs h_addr_list[0] de la structure hostent renvoyée.
Il y a 3 sources d'informations possibles: le fichier /etc/hosts, les pages jaunes (ypcat hosts), les serveurs de noms appelés DNS (Domain Name Services). La configuration du système permet de rendre transparent les appels à ces 3 sources. Il reste 2 appels:
getservent?
Les interrogations du serveur de noms effectuées par gethostbyname() utilise les éléments suivants : le serveur de noms named(8), les lignes de /etc/hosts, et l'annuaire Network Information Service (NIS), suivant le contenu de la ligne order du fichier /etc/host.conf.
comment ne pas manipuler des numéros de machines, mais plutôt des noms
Il y a 2 sources d'informations possibles: le fichier (/etc/hosts), les serveurs de noms appelés DNS (Domain Name Services)
struct hostent * gethostbyname (const char * name);
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 IP en notation pointée standard.
Si name est une adresse IP, aucune recherche supplémentaire n’a lieu
gethostbyname() utilise le serveur de noms named et le fichier/etc/hosts. L'action par défaut consiste à interroger named, puis /etc/hosts.
gethostbyname() copie simplement la chaine name dans le champ h_name et le champs équivalent struct in_addr dans le champs h_addr_list[0] de la structure hostent renvoyée.
Il y a aussi SOCK_RAW
la valeur 0 emploie le protocole par défaut selon le type : càd : TCP pour SOCK_STREAM ou UDP pour SOCK_DGRAM
AF_INET : Address Family INET (Internet)
pour restituer la structure de données:
int close (int socket)
Len : longueur de la structure : loc_addr
pour restituer la structure de données:
Changer nomme par désigne
Il faut bien expliquer ces figures
le paramètre sockfd permet au système de fournir au destinataire l'adresse externe (machine, port), pour l'envoi d'une éventuelle réponse