{ protocole, adresse locale, port local, adresse distante, port distant }Un socket est une demi-association spécifiant un côté de la connexion :
{ protocole, adresse locale, port local} { protocole, adresse distante, port distant}Certains appels système nécessitent un pointeur vers une adresse de sockets. Dans <sys/socket.h>, on trouve la définition générique des structures contenant une adresse de sockets :
struct sockaddr { u_short sa_family; /* address family */ char sa_data[14]; /* up to 14 bytes of direct address */ };Le contenu des 14 bytes doit être interprété suivant le type d'adresse. Généralement, des structures d'adresses sont redéfinies pour chaque famille d'adresses. Pour les protocoles internets, la structure des adresses est définie de la façon suivante dans <netinet/in.h> :
struct sockaddr_in { short sin_family; /* Address family (type) */ u_short sin_port; /* Port to connect to */ struct in_addr sin_addr; /* Host's adress */ char sin_zero[8]; /* padding, ignored */ };Pour pouvoir utiliser le socket, nous devons d'abord le créer grâce à l'appel système socket. La marche à suivre varie suivant le côté où l'on se trouve (client ou serveur) ainsi que le protocole utilisé (UDP, TCP, ...).
Elle peut être résumée par le dessin suivant (voir aussi exemple):
Elle peut être résumée par le dessin suivant (voir aussi exemple):
#include <sys/types.h> #include <sys/sochet.h> int socket(int domain, int type, int protocol);socket crée un nouveau socket tout en précisant son type de protocole dans les paramètres domain et type.
Cet appel système retourne -1 en cas d'erreur sinon le descripteur du socket.
Il est important de noter que seule la partie protocole associée au socket est initialisée. Les autres le seront par d'autres appels système.
Exemple:
descripteur = socket(PF_INET, SOCK_STREAM, 0)crée un nouveau socket de type TCP-IP et retourne son descripteur lorsque l'opération s'est correctement déroulée.
#include <sys/types.h> #include <sys/sochet.h> int bind(int s, const struct sockaddr *name, int namelen);bind définit l'adresse locale et le port local de l'association. Pour TCP/IP, le second argument sera const struct sockaddr_in * name. namelen est la taille effective de la structure pointée par le second argument.
Exemple:
local_addr->sin_family = AF_INET; local_addr->sin_addr.s_addr = htonl(INADDR_ANY); local_addr->sin_port = htons(portnum); bind(s, (struct sockaddr *)local_addr,sizeof(struct sockaddr_in))initialise l'adresse locale à celle d'une interface de la machine et le port local de l'association à
portnum
.
#include <sys/types.h> #include <sys/sochet.h> int connect(int s, struct sockaddr *name, int namelen);connect est utilisé par un serveur pour établir une connexion avec un serveur.
Le client n'a pas besoin de faire un bind avant connect : l'établissement de la connexion définit les 4 éléments : adresse locale, port local, adresse distante, port distant. Une adresse locale libre est assignée par connect.
Dans un protocol connection-oriented, connect ne rend la main que quand la connexion est établie ou qu'une erreur se produit.
Un client connectionless peut aussi utiliser connect. Il n'y a, cependant, pas établissement de connexion. Simplement, l'adresse du socket du serveur est stockée et n'a pas besoin d'être spécifiée lors de chaque envoie.
connect retourne 0 si tous s'est bien déroulé sinon -1.
Par exemple,
toinfo = gethostbyname(htoname) toaddr = *(u_long *)toinfo->h_addr_list[0]; to->sin_family = AF_INET; to->sin_addr.s_addr = toaddr; to->sin_port = htonl(portnum); connect(s,(struct sockaddr *)to,sizeof(struct sockaddr_in))connecte le socket ``
s
'' du processus client sur le port
``portnum
'' de l'hôte (serveur) portant le nom ``htoname
''.
#include <sys/types.h> #include <sys/sochet.h> int listen(int s, int backlog);listen est utilisé par un serveur connection-oriented pour indiquer qu'il est disposé à accepter des connexions.
listen retourne -1 en cas d'erreur sinon 0.
Exemple:
listen(s,5)indique que le serveur est disposé à recevoir des demandes de connexion en ayant fixé à 5 le nombre de connexions en attente d'être acceptées.
#include <sys/types.h> #include <sys/sochet.h> int accept(int s, struct sockaddr *addr, int *addrlen);Après un listen, un serveur connection-oriented peut attendre une demande de connexion d'un client par accept.
accept extrait la première demande de connexion en attente et crée un nouveau socket ayant les mêmes propriétés que s. S'il n'y a pas de demande en attente, accept bloque le processus appelant jusqu'à l'arrivée d'une demande.
peer_addr est un argument résultat qui retourne l'adresse (socket) du client connecté.
addrlen est un argument valeur-résultat : avant l'appel, il pointe vers la taille effective de la structure retournée.
Le socket s passé à accept n'a que 3 éléments de son association définis : le protocole, l'adresse locale et le port local. Le nouveau socket retourné par accept a son association complètement définie. Le socket s par contre reste dans le même état. Ceci permet au processus d'accepter d'autres connexions sur le même socket (serveur concurrent).
accept retourne -1 en cas d'erreur sinon le descripteur du socket.
Exemple:
fromlen = sizeof(struct sockaddr_in); s1 = accept(s,(struct sockaddr *)peer_addr,&fromlen))retourne dans
s1
, un nouveau descripteur de socket
possédant les mêmes propriétés que s
et dans peer_addr
, les informations à propos du
client qui vient d'établir la connexion. fromlen
est
initialisé après l'appel système à la taille
effective de peer_addr
.
#include <sys/types.h> #include <sys/sochet.h> int send(int s, const char *msg, int len, int flags); int sendto(int s, const char *msg, int len, int flags, const struct sockaddr *to, int tolen); int recv(int s, char *buf, int len, int flags); int recvfrom(int s, char *buf, int len, int flags, struct sockaddr *from, int *fromlen);send et sendto sont utilisés pour envoyer un message msg de taille len à un destinataire. Dans le cas d'une association connectionless, seul sendto peut être utilisé. Le paramètre to de taille tolen présent dans sendto sert à désigner le destinataire.
recv et recvfrom sont utilisés pour réceptionner des messages. Dans le cas d'une association connectionless, seul recvfrom peut être utilisé. Le paramètre from de taille fromlen présent dans rcvfrom permet de connaître l'expéditeur.
Tous ces appels systèmes retournent -1 en cas d'erreur sinon la taille des données effectivement envoyées ou lues.
#include <sys/types.h> #include <sys/sochet.h> int close(int fildes); int shutdown(int s, int how);close ferme un socket. Si ce socket est associé à un protocole garantissant une transmission fiable (ex : TCP), le système essaie d'envoyer les données restantes à envoyer.
shutdown permet de fermer un des deux sens (ou les deux) d'une connexion full-duplex, suivant la valeur de howto :
#include <sys/types.h> #include <sys/socket.h> int getsockname(int s, struct sockaddr *name, int *namelen);Cet appel système retourne -1 en cas d'erreur sinon 0 ainsi que dans name, le nom du socket s et dans namelen, sa longueur.
int getpeername(int s, struct sockaddr *name, int *namelen);Cet appel système retourne -1 en cas d'erreur sinon 0 ainsi que dans name, le nom associé au socket auquel le socket s est connecté et dans namelen, la longueur de ce nom.