Beruflich Dokumente
Kultur Dokumente
Sommaire
Linterface socket 2
Pr-requis . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2
Dfinition . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2
Manuel du pogrammeur . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2
Modle . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
Couche Transport . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
Numro de ports . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
Caractristiques des sockets . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
Manipulations 5
Objectifs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
tape n1 : cration de la socket (ct client) . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
tape n2 : connexion au serveur . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
tape n3 : vrification du bon fonctionnement de la connexion . . . . . . . . . . . . . . . . . 9
tape n4 : change des donnes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
tape n5 : ralisation dun serveur TCP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13
tape n6 : mise en attente des connexions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16
tape n7 : accepter les demandes connexions . . . . . . . . . . . . . . . . . . . . . . . . . . . 18
Bilan . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23
Questions de rvision 24
1
LINTERFACE SOCKET
Linterface socket
Pr-requis
La mise en oeuvre de linterface socket ncessite de connatre :
Larchitecture client/serveur
Ladressage IP et les numros de port
Notions dAPI (appels systmes sous Unix) et de programmation en langage C
Les protocoles TCP et UDP, les modes connect et non connect
Dfinition
La notion de socket a t introduite dans les distributions de Berkeley (un fameux
systme de type UNIX, dont beaucoup de distributions actuelles utilisent des morceaux
de code), cest la raison pour laquelle on parle parfois de sockets BSD (Berkeley Software
Distribution).
Il sagit dun modle permettant la communication inter processus (IPC - Inter Process Communication)
afin de permettre divers processus de communiquer aussi bien sur une mme machine qu travers un
rseau TCP/IP. [Wikipedia]
Manuel du pogrammeur
Le dveloppeur utilisera donc concrtement une interface pour programmer une application TCP/IP
grce par exemple :
lAPI Socket BSD sous Unix/Linux ou
lAPI WinSocket sous Microsoft Windows
Les pages man principales sous Unix/Linux concernant la programmation rseau sont regroupes dans le
chapitre 7 :
socket(7) : interface de programmation des sockets
packet(7) : interface par paquet au niveau priphrique
raw(7) : sockets brutes (raw) IPv4 sous Linux
ip(7) : implmentation Linux du protocole IPv4
udp(7) : protocole UDP pour IPv4
tcp(7) : protocole TCP
L'accs aux pages man se fera donc avec la commande man, par exemple : man 7 socket
Modle
Rappel : une socket est un point de communication par lequel un processus peut mettre et recevoir des
donnes.
Ce point de communication devra tre reli une adresse IP et un numro de port dans le cas des
protocoles Internet.
Une socket est communment reprsente comme un point dentre initial au niveau TRANSPORT du
modle couches DoD dans la pile de protocole.
Couche Transport
Rappel : la couche Transport est responsable du transport des messages complets de bout en bout (soit
de processus processus) au travers du rseau.
En programmation, si on utilise comme point dentre initial le niveau TRANSPORT, il faudra alors
choisir un des deux protocoles de cette couche :
TCP (Transmission Control Protocol) est un protocole de transport fiable, en mode connect (RFC
793).
UDP (User Datagram Protocol) est un protocole souvent dcrit comme tant non-fiable, en mode
non-connect (RFC 768), mais plus rapide que TCP.
Numro de ports
Rappel : un numro de port sert identifier un processus (lapplication) en cours de communication
par lintermdiaire de son protocole de couche application (associ au service utilis, exemple : 80 pour
HTTP).
Pour chaque port, un numro lui est attribu (cod sur 16 bits), ce qui implique qu'il existe un maximum
de 65 536 ports (216 ) par machine et par protocoles TCP et UDP.
Lattribution des ports est faite par le systme dexploitation, sur demande dune application. Ici, il faut
distinguer les deux situations suivantes :
cas dun processus client : le numro de port utilis par le client sera envoy au processus serveur.
Dans ce cas, le processus client peut demander ce que le systme dexploitation lui attribue nimporte
quel port, condition quil ne soit pas dj attribu.
cas dun processus serveur : le numro de port utilis par le serveur doit tre connu du processus client.
Dans ce cas, le processus serveur doit demander un numro de port prcis au systme dexploitation
qui vrifiera seulement si ce numro nest pas dj attribu.
Une liste des ports dits rservs est disponible dans le chier /etc/services sous Unix/Linux.
Une socket appartient une famille. Il existe plusieurs types de sockets. Chaque famille possde son
adressage.
Manipulations
Objectifs
Lobjectif de cette partie est la mise en oeuvre dune communication client/serveur en utilisant une socket
TCP sous Unix/Linux.
NOM
socket - Crer un point de communication
SYNOPSIS
#include <sys/types.h> /* Voir NOTES */
#include <sys/socket.h>
DESCRIPTION
socket() cre un point de communication, et renvoie un descripteur.
...
VALEUR RENVOYE
Cet appel systme renvoie un descripteur rfrenant la socket cre sil russit.
Sil choue, il renvoie -1 et errno contient le code derreur.
...
Extrait de la page man de lappel systme socket
laide dun diteur de texte (vi, vim, emacs, kwrite, kate, gedit, ... sous Linux), tapez ( la main, pas
de copier/coller, histoire de bien mmoriser !) le programme suivant dans un fichier que vous nommerez
"clientTCP-1.c" :
#include <stdio.h>
#include <stdlib.h> /* pour exit */
#include <sys/types.h>
#include <sys/socket.h>
int main()
{
int descripteurSocket;
//--Fin de ltape n1 !
printf("Socket cre avec succs ! (%d)\n", descripteurSocket);
return 0;
}
Un client TCP en C (itration 1)
Pour le paramtre protocol, on a utilis la valeur 0 (voir commentaire). On aurait pu prciser le protocole
TCP de la manire suivante : IPPROTO_TCP.
NOM
connect - Dbuter une connexion sur une socket
SYNOPSIS
#include <sys/types.h> /* Voir NOTES */
#include <sys/socket.h>
DESCRIPTION
Lappel systme connect() connecte la socket rfrence par le descripteur de fichier
sockfd ladresse indique par serv_addr. ...
VALEUR RENVOYE
connect() renvoie 0 sil russit, ou -1 sil choue, auquel cas errno contient le
code derreur. ...
Extrait de la page man de lappel systme connect
On rappelle que ladressage du processus distant dpend du domaine de communication (cad la famille
de protocole employe). Ici, nous avons choisi le domaine PF_INET pour les protocoles Internet IPv4.
Dans cette famille, un processus sera identifi par :
une adresse IPv4
un numro de port
struct in_addr { unsigned int s_addr; }; // une adresse Ipv4 (32 bits)
struct sockaddr_in
{
unsigned short int sin_family; // <- PF_INET
unsigned short int sin_port; // <- numro de port
struct in_addr sin_addr; // <- adresse IPv4
unsigned char sin_zero[8]; // ajustement pour tre compatible avec sockaddr
};
La structure compatible sockaddr_in pour PF_INET
Il suffit donc dinitialiser une structure sockaddr_in avec les informations distantes du serveur (adresse
IPv4 et numro de port).
Pour crire ces informations dans la structure dadresse, il nous faudra utiliser :
inet_aton() pour convertir une adresse IP depuis la notation IPv4 dcimale pointe vers une forme
binaire (dans lordre doctet du rseau)
htons() pour convertir le numro de port (sur 16 bits) depuis lordre des octets de lhte vers celui
du rseau.
L'ordre des octets du rseau est en fait big-endian. Il est donc plus prudent d'appeler des fonctions qui
respectent cet ordre pour coder des informations dans les en-ttes des protocoles rseaux.
int main()
{
int descripteurSocket;
struct sockaddr_in pointDeRencontreDistant;
socklen_t longueurAdresse;
Ceci peut sexpliquer tout simplement parce quil ny a pas de processus serveur cette adresse !
Puis :
$ ./clientTCP-2
Socket cre avec succs ! (3)
Connexion au serveur russie avec succs !
Dans l'architecture client/serveur, on rappelle que c'est le client qui a l'initiative de l'change. Il faut donc
que le serveur soit en coute avant que le client fasse sa demande.
Normalement les octets envoys ou reus respectent un protocole de couche APPLICATION. Ici, pour
les tests, notre couche APPLICATION sera vide ! C'est--dire que les donnes envoyes et reues ne
respecteront aucun protocole et ce seront de simples caractres ASCII.
Les appels recv() et send() sont spciques aux sockets en mode connect. La seule dirence avec
read() et write() est la prsence de flags (cf. man 2 send).
Faire communiquer deux processus sans aucun protocole de couche APPLICATION est tout de mme
difficile ! On va simplement fixer les rgles dchange suivantes :
le client envoie en premier une chane de caractres
et le serveur lui rpondra "ok"
int main()
{
int descripteurSocket;
struct sockaddr_in pointDeRencontreDistant;
socklen_t longueurAdresse;
char messageEnvoi[LG_MESSAGE]; /* le message de la couche Application ! */
char messageRecu[LG_MESSAGE]; /* le message de la couche Application ! */
int ecrits, lus; /* nb doctets ecrits et lus */
int retour;
return 0;
}
Un client TCP en C (itration 3)
On utilise la mme procdure de test que prcdemment en dmarrant un serveur netcat sur le port
5000 :
$ nc -l -p 5000
(3 octets)
Dans netcat, pour envoyer des donnes au client, il sut de saisir son message et de valider par la touche
Entre.
Que se passe-t-il si le serveur sarrte (en tapant Ctrl-C par exemple !) au lieu denvoyer
"ok" ?
$ nc -l -p 5000
Hello world !
^C
$ ./clientTCP-3
Socket cre avec succs ! (3)
Connexion au serveur russie avec succs !
Message Hello world !
envoy avec succs (14 octets)
NOM
shutdown - Terminer une communication en full-duplex
SYNOPSIS
#include <sys/socket.h>
DESCRIPTION
La fonction shutdown() termine tout ou partie dune connexion full-duplex sur la
socket s. Si how vaut SHUT_RD, la rception est dsactive.
Si how vaut SHUT_WR, lmission est dsactive. Si how vaut SHUT_RDWR, lemission et
la rception sont dsactives.
VALEUR RENVOYE
Cet appel systme renvoie 0 sil russit, ou -1 sil choue, auquel cas errno
contient le code derreur.
...
Extrait de la page man de lappel systme shutdown
NOM
bind - Fournir un nom une socket
SYNOPSIS
#include <sys/types.h> /* Voir NOTES */
#include <sys/socket.h>
DESCRIPTION
Quand une socket est cre avec lappel systme socket(2), elle existe dans lespace
des noms mais na pas de nom assign). bind() affecte ladresse spcifie dans addr
la socket rfrence par le descripteur de fichier sockfd. addrlen indique la taille,
en octets, de la structure dadresse pointe par addr. Traditionnellement cette
opration est appele affectation dun nom une socket .
Il est normalement ncessaire daffecter une adresse locale avec bind() avant quune
socket SOCK_STREAM puisse recevoir des connexions (voir accept(2)).
VALEUR RENVOYE
Lappel renvoie 0 sil russit, ou -1 sil choue, auquel cas errno contient le code
derreur.
...
Extrait de la page man de lappel systme bind
On rappelle que ladressage dun processus (local ou distant) dpend du domaine de communication
(cad la famille de protocole employe). Ici, nous avons choisi le domaine PF_INET pour les protocoles
Internet IPv4.
Dans cette famille, un processus sera identifi par :
une adresse IPv4
un numro de port
Rappel : linterface socket propose une structure dadresse gnrique sockaddr et le domaine PF_INET
utilise une structure compatible sockaddr_in.
Il suffit donc dinitialiser une structure sockaddr_in avec les informations locales du serveur (adresse
IPv4 et numro de port).
Pour crire ces informations dans la structure dadresse, il nous faudra utiliser :
htonl() pour convertir une adresse IP (sur 32 bits) depuis lordre des octets de lhte vers celui du
rseau
htons() pour convertir le numro de port (sur 16 bits) depuis lordre des octets de lhte vers celui du
rseau.
Normalement il faudrait indiquer l'adresse IPv4 de l'interface locale du serveur qui acceptera les demandes
de connexions. Il est ici possible de prciser avec INADDR_ANY que toutes les interfaces locales du serveur
accepteront les demandes de connexion des clients.
int main()
{
int socketEcoute;
struct sockaddr_in pointDeRencontreLocal;
socklen_t longueurAdresse;
return 0;
}
Un serveur TCP en C (itration 1)
Attention, tout de mme de bien comprendre quun numro de port identifie un processus communiquant !
Excutons deux fois le mme serveur et on obtient alors :
$ ./serveurTCP-1 & ./serveurTCP-1
Socket cre avec succs ! (3)
Socket attache avec succs !
Socket cre avec succs ! (3)
bind: Address already in use
Explication : l'attachement local au numro de port 5000 du deuxime processus choue car ce numro
de port est dj attribu par le systme d'exploitation au premier processus serveur.
NOM
listen - Attendre des connexions sur une socket
SYNOPSIS
#include <sys/types.h> /* Voir NOTES */
#include <sys/socket.h>
DESCRIPTION
listen() marque la socket rfrence par sockfd comme une socket passive, cest--
dire comme une socket qui sera utilise pour accepter les demandes de connexions
entrantes en utilisant accept().
Largument sockfd est un descripteur de fichier qui fait rfrence une socket de
type SOCK_STREAM.
Largument backlog dfinit une longueur maximale jusqu laquelle la file des
connexions en attente pour sockfd peut crotre. Si une nouvelle connexion arrive
alors que la file est pleine, le client reoit une erreur indiquant ECONNREFUSED,
ou, si le protocole sous-jacent supporte les retransmissions, la requte peut tre
ignore afin quun nouvel essai russisse.
VALEUR RENVOYE
Cet appel systme renvoie 0 si il russit, ou -1 en cas dchec, auquel cas errno est
renseigne en consquence.
...
Extrait de la page man de lappel systme listen
Si la le est pleine, le serveur sera dans une situation de DOS (Deny Of Service ) car il ne peut plus traiter
les nouvelles demandes de connexion.
int main()
{
int socketEcoute;
struct sockaddr_in pointDeRencontreLocal;
socklen_t longueurAdresse;
NOM
accept - Accepter une connexion sur une socket
SYNOPSIS
#include <sys/types.h> /* Voir NOTES */
#include <sys/socket.h>
DESCRIPTION
Lappel systme accept() est employ avec les sockets utilisant un protocole en mode
connect SOCK_STREAM. Il extrait la premire connexion de la file des connexions
en attente de la socket sockfd lcoute, cre une nouvelle socket connecte, et
renvoie un nouveau descripteur de fichier qui fait rfrence cette socket.
La nouvelle socket nest pas en tat dcoute. La socket originale sockfd nest pas
modifie par lappel systme.
...
VALEUR RENVOYE
Sil russit, accept() renvoie un entier non ngatif, constituant un descripteur pour
la nouvelle socket. Sil choue, lappel renvoie -1 et errno contient le code d
erreur.
...
Extrait de la page man de lappel systme accept
Explication : imaginons qu'un client se connecte notre socket d'coute. L'appel accept() va retourner
une nouvelle socket connecte au client qui servira de socket de dialogue. La socket d'coute reste
inchange et peut donc servir accepter des nouvelles connexions.
Le principe est simple mais un problme apparat pour le serveur : comment dialoguer avec le client
connect et continuer attendre des nouvelles connexions ? Il y a plusieurs solutions ce problme
notamment la programmation multi-tche car ici le serveur a besoin de parallliser plusieurs traitements.
On va pour linstant ignorer ce problme et mettre en oeuvre un serveur basique : cest--dire mono-client
(ou plus exactement un client aprs lautre) !
#include <sys/types.h>
#include <sys/socket.h>
#include <string.h> /* pour memset */
#include <netinet/in.h> /* pour struct sockaddr_in */
#include <arpa/inet.h> /* pour htons et inet_aton */
#include <unistd.h> /* pour sleep */
int main()
{
int socketEcoute;
struct sockaddr_in pointDeRencontreLocal;
socklen_t longueurAdresse;
int socketDialogue;
struct sockaddr_in pointDeRencontreDistant;
char messageEnvoi[LG_MESSAGE]; /* le message de la couche Application ! */
char messageRecu[LG_MESSAGE]; /* le message de la couche Application ! */
int ecrits, lus; /* nb doctets ecrits et lus */
int retour;
// On fixe la taille de la file dattente 5 (pour les demandes de connexion non encore
traites)
if(listen(socketEcoute, 5) < 0)
{
perror("listen");
exit(-3);
}
if (socketDialogue < 0)
{
perror("accept");
close(socketDialogue);
close(socketEcoute);
exit(-4);
}
close(socketDialogue);
exit(-6);
case 0 : /* la socket est ferme */
fprintf(stderr, "La socket a t ferme par le client !\n\n");
close(socketDialogue);
return 0;
default: /* envoi de n octets */
printf("Message %s envoy (%d octets)\n\n", messageEnvoi, ecrits);
}
return 0;
}
Un serveur TCP en C (itration 3)
Message ok
envoy (3 octets)
Message ok
envoy (3 octets)
^C
$ ./clientTCP-3
Socket cre avec succs ! (3)
Connexion au serveur russie avec succs !
Message Hello world !
envoy avec succs (14 octets)
Il est videmment possible de tester notre serveur avec des clients TCP existants comme telnet ou
netcat.
Bilan
Lchange entre un client et un serveur TCP peut tre maintenant schmatis de la manire suivante :
Questions de rvision
Lide de base des questions de rvision est de vous donner une chance de voir si vous avez identifi et
compris les points cls de ce TP.
Question 3. Quelles sont les deux informations qui dfinissent un point de communication en IPv4 ?
Question 6. quelle couche du modle DoD est relie linterface de programmation socket ?
Question 7. Quel protocole de niveau Transport permet dtablir une communication en mode connect ?
Question 8. Quel protocole de niveau Transport permet dtablir une communication en mode non-
connect ?
Question 10. quels protocoles correspond le domaine PF_INET ou AF_INET ? Est-ce le seul utilisable
avec linterface socket ? En citer au moins un autre.