Berkeley sockets
Un article de Wikipédia, l'encyclopédie libre.
Les Berkeley sockets, que l'on pourrait traduire par « connecteurs réseau de Berkeley[1] », représentent une interface de programmation pour les communications entre processus — Interprocess communication — . Elles ont été introduites pour la première fois dans la version 4.3BSD (1986) de l'UNIX de l'université de Berkeley. Avant leur introduction, le seul mécanisme standard qui permettait à deux processus de communiquer se faisait par l'intermédiaire des pipes.
Sommaire |
[modifier] Généralités
La communication se fait à l'aide d'une socket. Une socket représente un point terminal d'un canal de communication entre deux ou plusieurs processus — un nom peut lui être attribué.
Chaque socket possède un type et un ou plusieurs processus qui lui sont associés. Elle est également caractérisée par le domaine de communication dans lequel elle se trouve. Ce dernier est une abstraction qui permet de regrouper les processus ayant des propriétés communes et communiquant par l'intermédiaire de sockets. Normalement, une socket ne peut échanger des données qu'avec une socket se trouvant dans le même domaine de communication.
La communication inter-processus de 4.3BSD supportait trois domaines de communication:
- le domaine Unix dans lequel deux processus se trouvant sur la même station Unix uniquement peuvent communiquer, [2]
- le domaine Internet pour les processus utilisant le protocole TCP/IP pour communiquer entre eux,
- le domaine NS pour les processus échangeant des données en utilisant le protocole standard de Xerox.
[modifier] Types de sockets
Les différents types de sockets dépendent de quelques propriétés visibles par le programmeur. Rien n'empêche deux sockets de types différents de communiquer entre eux si le protocole utilisé le supporte — même si les processus sont supposés communiquer uniquement par des sockets de même type.
Il existe généralement quatre types de sockets. Une socket stream permet une communication bidirectionnelle, sûre, séquencée et un flux de données sans duplication pouvant entraîner une fragmentation des paquets transmis.
Une socket datagram permet une communication bidirectionnelle qui n'est pas séquencée, pas sûre, et peut éventuellement entraîner une duplication des données. Un processus utilisant ce type de socket peut donc recevoir les données dans un ordre différent de l'ordre de départ. Par contre, aucune fragmentation n'est effectuée sur les paquets transmis. Ce type de socket est par exemple utilisée dans les réseaux à commutation de paquets comme Ethernet.
Une socket raw permet aux utilisateurs d'accéder à des protocoles de communication différents en même temps. Les sockets raw ne sont pas destinées aux utilisateurs courants — seul l'utilisateur root peut y avoir accès sur la plupart des systèmes UNIX® — elles permettent d'avoir accès aux données "brutes" et sont utilisées par exemple pour analyser le trafic d'un réseau.
Une socket sequenced packet ressemble à une socket stream sauf qu'elle n'utilise pas de fragmentations de paquets.
[modifier] Création d'une socket
La création d'une socket se fait à partir de l'appel système suivant:
#include <sys/types.h>
#include <sys/socket.h>
int s, domain, type, protocol;
s = socket (domain, type, protocol);
Cet appel système permet de créer une socket appartenant à domain et possédant la propriété type. Il renvoit un nombre entier — -1 en cas d'échec — qui peut être assimilé à un descripteur de fichier . Le champ protocol peut ne pas être spécifié — valeur égale à zéro. Dans ce cas, le système choisit un protocole approprié parmi les différents protocoles utilisés dans le domaine de communication considéré et supportant le type de socket requis.
Les champs domain et type sont choisis parmi les constantes définies dans le fichier <sys/socket.h>. Pour le domaine UNIX par exemple, la constante est AF_UNIX [3] — AF_INET pour le domaine internet et AF_NS pour le domaine NS. Les types de sockets sont les suivants: SOCK_STREAM, SOCK_DGRAM, SOCK_RAW, SOCK_NS. Par exemple pour créer une socket utilisant le protocole TCP, l'appel système suivant peut être effectué:
int s;
s = socket (AF_INET, SOCK_STREAM, 0);
La plupart du temps, la valeur par défaut du champ protocol est suffisante — même si on peut lui attribuer une valeur particulière.
[modifier] Attribution d'un nom
Une socket est créée sans nom et ne permet pas tout de suite d'échanger des données. Pour pouvoir y remédier, il faut lui associer une adresse. Pour les domaines Internet et NS, cette association est composée d'une adresse locale et d'un port local et d'une adresse distante et d'un port distant — tandis que pour le domaine UNIX, il s'agit de répertoires local et distant [4].
L'adresse générique d'une socket est définie par la structure suivante:
#define SOCK_MAXADDRLEN 255 /* adresse la plus longue possible */
struct sockaddr {
unsigned char sa_len; /* longueur totale */
sa_family_t sa_family; /* famille d'adresse */
char sa_data[14]; /* valeur de l'adresse */
};
Cette adresse n'est généralement pas directement ulilisé en tant que telle — servant uniquement de référence générique pour les appels systèmes. À la place, une adresse plus spécifique est utilisée pour chaque domaine de communication. Pour le domaine internet par exemple, la structure suivante — définie dans le fichier netinet/in.h — remplace la version précédente:
struct sockaddr_in {
uint8_t sin_len; /* longueur totale */
sa_family sin_family; /* famille d'adresse */
in_port_t sin_port; /* numero de port */
struct in_addr sin_addr; /* valeur sur 32 bits de l'adresse */
char sin_zero[8]; /* champ rempli de zeros */
};
De la même maniere, il existe également une adresse sockaddr_un et sockaddr_ns pour les domaines unix et NS.
L'association d'une socket avec une adresse se fait par l'intermediaire de l'appel système bind:
#include <sys/types.h>
#include <sys/socket.h>
int bind (int s, const struct sockaddr *addr, socklen_t addrlen);
ou s est la socket associée avec l'adresse pointée par addr dont la longueur totale est addrlen. La fonction renvoie -1 en cas d'échec. Après avoir effectué cette operation, la socket est desormais referencée et peut donc recevoir et envoyer des données.