Vous êtes sur la page 1sur 20

TP Dveloppement Rseau n2 : Socket UDP

2012 tv <tvaira@free.fr> - v.1.0

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 : attachement local de la socket . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
tape n3 : communication avec le serveur . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
tape n4 : vrification du bon fonctionnement de lchange . . . . . . . . . . . . . . . . . . . 12
tape n4 : ralisation dun serveur UDP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13
Bilan . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16

Questions de rvision 17

Travail demand 17
Exercice 1 : client UDP amlior . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17
Exercice 2 : serveur UDP amlior . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18
Exercice 3 : une messagerie instantane en UDP . . . . . . . . . . . . . . . . . . . . . . . . . . 18

Les objectifs de ce tp sont de mettre en oeuvre la programmation rseau en utilisant


linterface socket pour le mode non-connect (UDP).
Remarque : les tp ont pour but dtablir ou de renforcer vos comptences pratiques. Vous pouvez penser
que vous comprenez tout ce que vous lisez ou tout ce que vous a dit votre enseignant mais la rptition et
la pratique sont ncessaires pour dvelopper des comptences en programmation. Ceci est comparable au
sport ou la musique ou tout autre mtier demandant un long entranement pour acqurir lhabilet
ncessaire. Imaginez quelquun qui voudrait disputer une compttion dans lun de ces domaines sans
pratique rgulire. Vous savez bien quel serait le rsultat.

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).

Intgration d'IP dans Unix BSD (1981)


Interface de programmation socket  de Berkeley (1982) : la plus utilise et intgre dans le noyau

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]

Socket : mcanisme de communication bidirectionelle entre processus

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

Pour Microsoft Windows, on pourra utiliser le service en ligne MSDN :


Windows Socket 2 : msdn.microsoft.com/en-us/library/ms740673(VS.85).aspx
Les fonctions Socket : msdn.microsoft.com/en-us/library/ms741394(VS.85).aspx

TP Dveloppement Rseau n2 : Socket UDP 2 / 20 2012 tv <tvaira@free.fr>


LINTERFACE 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.

Exemple de processus TCP et UDP

TP Dveloppement Rseau n2 : Socket UDP 3 / 20 2012 tv <tvaira@free.fr>


LINTERFACE SOCKET

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.

Caractristiques des sockets


Rappel : les sockets compatibles BSD reprsentent une interface uniforme entre le processus utilisateur
(user) et les piles de protocoles rseau dans le noyau (kernel) de lOS.
Pour dialoguer, chaque processus devra pralablement crer une socket de communication en indiquant :
le domaine de communication : ceci slectionne la famille de protocole employer. Il faut savoir que
chaque famille possde son adressage. Par exemple pour les protocoles Internet IPv4, on utilisera le
domaine PF_INET.
le type de socket utiliser pour le dialogue. Pour PF_INET, on aura le choix entre : SOCK_STREAM (qui
correspond un mode connect), SOCK_DGRAM (qui correspond un mode non connect) ou SOCK_RAW
(qui permet un accs direct aux protocoles de la couche Rseau comme IP, ICMP, ...).
le protocole utiliser sur la socket. Le numro de protocole dpend du domaine de communication et
du type de la socket. Normalement, il ny a quun seul protocole par type de socket pour une famille
donne (SOCK_STREAM TCP et SOCK_DGRAM UDP). Nanmoins, rien ne soppose ce que plusieurs
protocoles existent, auquel cas il est ncessaire de le spcifier (cest la cas pour SOCK_RAW o il faudra
prciser le protocole utiliser).

TP Dveloppement Rseau n2 : Socket UDP 4 / 20 2012 tv <tvaira@free.fr>


MANIPULATIONS

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 UDP sous Unix/Linux.

tape n1 : cration de la socket (ct client)


Pour crer une socket, on utilisera lappel systme socket(). On commence par consulter la page du
manuel associe cet appel :
$ man 2 socket

SOCKET(2) Manuel du programmeur Linux SOCKET(2)

NOM
socket - Crer un point de communication

SYNOPSIS
#include <sys/types.h> /* Voir NOTES */
#include <sys/socket.h>

int socket(int domain, int type, int protocol);

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
"clientUDP-1.c" :
#include <stdio.h>
#include <stdlib.h> /* pour exit */
#include <sys/types.h>
#include <sys/socket.h>

int main()
{
int descripteurSocket;

TP Dveloppement Rseau n2 : Socket UDP 5 / 20 2012 tv <tvaira@free.fr>


MANIPULATIONS

//<-- Dbut de ltape n1 !


// Cre un socket de communication
descripteurSocket = socket(PF_INET, SOCK_DGRAM, 0); /* 0 indique que lon utilisera le
protocole par dfaut associ SOCK_DGRAM soit UDP */

// Teste la valeur renvoye par lappel systme socket()


if(descripteurSocket < 0) /* chec ? */
{
perror("socket"); // Affiche le message derreur
exit(-1); // On sort en indiquant un code erreur
}

//--> Fin de ltape n1 !


printf("Socket cre avec succs ! (%d)\n", descripteurSocket);

// On ferme la ressource avant de quitter


close(descripteurSocket);

return 0;
}
Un client UDP en C (itration 1)

Pour le paramtre protocol, on a utilis la valeur 0 (voir commentaire). On aurait pu prciser le protocole
UDP de la manire suivante : IPPROTO_UDP.

tape n2 : attachement local de la socket


Maintenant que nous avons cr une socket UDP, le client pourrait dj communiquer avec un serveur
UDP car nous utilisons un mode non-connect.

Un change en UDP

TP Dveloppement Rseau n2 : Socket UDP 6 / 20 2012 tv <tvaira@free.fr>


MANIPULATIONS

On va tout dabord attacher cette socket une interface et un numro de port local de sa machine en
utilisant utiliser lappel systme bind(). Cela revient crer un point de rencontre local pour le
client. On consulte la page du manuel associe cet appel :
$ man 2 bind

BIND(2) Manuel du programmeur Linux BIND(2)

NOM
bind - Fournir un nom une socket

SYNOPSIS
#include <sys/types.h> /* Voir NOTES */
#include <sys/socket.h>

int bind(int sockfd, const struct sockaddr *addr,


socklen_t addrlen);

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 .

Les rgles daffectation de nom varient suivant le domaine de communication.


...

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 client (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.

TP Dveloppement Rseau n2 : Socket UDP 7 / 20 2012 tv <tvaira@free.fr>


MANIPULATIONS

Normalement, il faudrait indiquer un numro de port utilis par le client pour cette socket. Cela peut
s'avrer dlicat si on ne connat pas les numros de port libres. Le plus simple est de laisser le systme
d'exploitation choisir en indiquant la valeur 0 dans le champ sin_port.

diter le programme suivant dans un fichier que vous nommerez "clientUDP-2.c" :


#include <stdio.h>
#include <stdlib.h> /* pour exit */
#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 htonl */

int main()
{
int descripteurSocket;
struct sockaddr_in pointDeRencontreLocal;
socklen_t longueurAdresse;

// Cre un socket de communication


descripteurSocket = socket(PF_INET, SOCK_DGRAM, 0);

// Teste la valeur renvoye par lappel systme socket()


if(descripteurSocket < 0) {
perror("socket"); // Affiche le message derreur
exit(-1); // On sort en indiquant un code erreur
}
printf("Socket cre avec succs ! (%d)\n", descripteurSocket);

//<-- Dbut de ltape n2 !


// On prpare ladresse dattachement locale
longueurAdresse = sizeof(struct sockaddr_in);
memset(&pointDeRencontreLocal, 0x00, longueurAdresse);
pointDeRencontreLocal.sin_family = PF_INET;
pointDeRencontreLocal.sin_addr.s_addr = htonl(INADDR_ANY); // nimporte quelle interface
locale disponible
pointDeRencontreLocal.sin_port = htons(0); // los choisira un numro de port libre

// On demande lattachement local de la socket


if((bind(descripteurSocket, (struct sockaddr *)&pointDeRencontreLocal, longueurAdresse))
< 0) {
perror("bind");
exit(-2);
}
//--> Fin de ltape n2 !
printf("Socket attache avec succs !\n");

// On ferme la ressource avant de quitter


close(descripteurSocket);
return 0;
}
Un client UDP en C (itration 2)

TP Dveloppement Rseau n2 : Socket UDP 8 / 20 2012 tv <tvaira@free.fr>


MANIPULATIONS

Le test est concluant :


$ ./clientUDP-2
Socket cre avec succs ! (3)
Socket attache avec succs !

tape n3 : communication avec le serveur


Il nous faut donc des fonctions pour crire (envoyer) et lire (recevoir) des octets dans la socket.

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 fonctions dchanges de donnes sur une socket UDP sont recvfrom() et sendto() qui permettent
la rception et lenvoi doctets sur un descripteur de socket en mode non-connect.

Les appels recvfrom() et sendto() sont spciques aux sockets en mode non-connect. Ils utiliseront
en argument une structure sockaddr_in pour PF_INET.

Ici, on limitera notre client lenvoi dune chane de caractres. Pour cela, on va utiliser lappel sendto() :
$ man 2 sendto

SEND(2) Manuel du programmeur Linux SEND(2)

NOM
sendto - Envoyer un message sur une socket

SYNOPSIS
#include <sys/types.h>
#include <sys/socket.h>

ssize_t sendto(int s, const void *buf, size_t len, int flags,


const struct sockaddr *to, socklen_t tolen);

DESCRIPTION
Lappel systme sendto() permet de transmettre un message
destination dune autre socket.

Le paramtre s est le descripteur de fichier de la socket mettrice. Ladresse de la


cible est fournie par to, tolen spcifiant sa taille. Le message se trouve dans
buf et a pour longueur len.
...

VALEUR RENVOYE
Sils russissent, ces appels systme renvoient le nombre de caractres mis. Sils
chouent, ils renvoient -1 et errno contient le code derreur.
...
Extrait de la page man de lappel systme sendto

TP Dveloppement Rseau n2 : Socket UDP 9 / 20 2012 tv <tvaira@free.fr>


MANIPULATIONS

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

Et il suffira donc dinitialiser une structure sockaddr_in avec les informations distantes du serveur
(adresse IPv4 et numro de port). Cela revient adresser le point de rencontre distant qui sera utilis
dans lappel sendto() par le client.
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.

diter le programme suivant dans un fichier que vous nommerez "clientUDP-3.c" :


#include <stdio.h>
#include <stdlib.h> /* pour exit */
#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, htonl et inet_aton */

#define LG_MESSAGE 256

int main()
{
int descripteurSocket;
struct sockaddr_in pointDeRencontreLocal;
struct sockaddr_in pointDeRencontreDistant;
socklen_t longueurAdresse;
char messageEnvoi[LG_MESSAGE]; /* le message de la couche Application ! */
int ecrits; /* nb doctets ecrits */
int retour;

// Cre un socket de communication


descripteurSocket = socket(PF_INET, SOCK_DGRAM, 0); /* 0 indique que lon utilisera le
protocole par dfaut associ SOCK_DGRAM soit UDP */

// Teste la valeur renvoye par lappel systme socket()


if(descripteurSocket < 0) /* chec ? */
{
perror("socket"); // Affiche le message derreur
exit(-1); // On sort en indiquant un code erreur
}
printf("Socket cre avec succs ! (%d)\n", descripteurSocket);

TP Dveloppement Rseau n2 : Socket UDP 10 / 20 2012 tv <tvaira@free.fr>


MANIPULATIONS

// On prpare ladresse dattachement locale


longueurAdresse = sizeof(struct sockaddr_in);
memset(&pointDeRencontreLocal, 0x00, longueurAdresse);
pointDeRencontreLocal.sin_family = PF_INET;
pointDeRencontreLocal.sin_addr.s_addr = htonl(INADDR_ANY); // nimporte quelle interface
locale disponible
pointDeRencontreLocal.sin_port = htons(0); // los choisira un numro de port libre

// On demande lattachement local de la socket


if((bind(descripteurSocket, (struct sockaddr *)&pointDeRencontreLocal, longueurAdresse))
< 0)
{
perror("bind");
exit(-2);
}
printf("Socket attache avec succs !\n");

//<-- Dbut de ltape n3


// Obtient la longueur en octets de la structure sockaddr_in
longueurAdresse = sizeof(pointDeRencontreDistant);
// Initialise 0 la structure sockaddr_in
memset(&pointDeRencontreDistant, 0x00, longueurAdresse);
// Renseigne la structure sockaddr_in avec les informations du serveur distant
pointDeRencontreDistant.sin_family = PF_INET;
// On choisit le numro de port dcoute du serveur
pointDeRencontreDistant.sin_port = htons(IPPORT_USERRESERVED); // = 5000
// On choisit ladresse IPv4 du serveur
inet_aton("192.168.52.2", &pointDeRencontreDistant.sin_addr); // modifier selon ses
besoins

// Initialise 0 le message
memset(messageEnvoi, 0x00, LG_MESSAGE*sizeof(char));

// Envoie un message au serveur


sprintf(messageEnvoi, "Hello world !\n");
ecrits = sendto(descripteurSocket, messageEnvoi, strlen(messageEnvoi), 0, (struct
sockaddr *)&pointDeRencontreDistant, longueurAdresse);
switch(ecrits)
{
case -1 : /* une erreur ! */
perror("sendto");
close(descripteurSocket);
exit(-3);
case 0 :
fprintf(stderr, "Aucune donne na t envoye !\n\n");
close(descripteurSocket);
return 0;
default: /* envoi de n octets */
if(ecrits != strlen(messageEnvoi))
fprintf(stderr, "Erreur dans lenvoie des donnes !\n\n");
else
printf("Message %s envoy avec succs (%d octets)\n\n", messageEnvoi, ecrits);
}

TP Dveloppement Rseau n2 : Socket UDP 11 / 20 2012 tv <tvaira@free.fr>


MANIPULATIONS

//--> Fin de ltape n3 !

// On ferme la ressource avant de quitter


close(descripteurSocket);

return 0;
}
Un client UDP en C (itration 3)

Si vous testez ce client (sans serveur), vous risquez dobtenir :


$ ./clientUDP-3
Socket cre avec succs ! (3)
Socket attache avec succs !
Message Hello world !
envoy avec succs (14 octets)

Le message a t envoy au serveur : ceci peut sexpliquer tout simplement parce que nous sommes en
mode non-connect.

Le protocole UDP ne prend pas en charge un mode able : ici, le client a envoy des donnes sans savoir
si un serveur tait prt les recevoir !

tape n4 : vrification du bon fonctionnement de lchange


Pour tester notre client, il nous faut quand mme un serveur ! Pour cela, on va utiliser loutil rseau
netcat en mode serveur (-l) UDP (-u) sur le port 5000 (-p 5000).
$ nc -u -l -p 5000

Puis :
$ ./clientUDP-3
Socket cre avec succs ! (3)
Socket attache avec succs !
Message Hello world !
envoy avec succs (14 octets)

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 attente avant que le client envoie ses donnes.

Le message a bien t reu et affich par le serveur netcat :


$ nc -u -l -p 5000
Hello world !

TP Dveloppement Rseau n2 : Socket UDP 12 / 20 2012 tv <tvaira@free.fr>


MANIPULATIONS

tape n4 : ralisation dun serveur UDP


Le code source dun serveur UDP basique est trs similaire celui dun client UDP. videmment, un serveur
UDP a lui aussi besoin de crer une socket SOCK_DGRAM dans le domaine PF_INET. Puis, il doit utiliser lappel
systme bind() pour lier sa socket dcoute une interface et un numro de port local sa machine
car le processus client doit connatre et fournir au moment de lchange ces informations.
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.

Il est ici possible de prciser avec INADDR_ANY que toutes les interfaces locales du serveur accepteront les
changes des clients.

Dans notre exemple, le serveur va seulement rceptionner un datagramme en provenance du client. Pour
cela, il va utiliser lappel systme recvfrom() :
$ man 2 recvfrom

RECV(2) Manuel du programmeur Linux RECV(2)

NOM
recvfrom - Recevoir un message sur une socket

SYNOPSIS
#include <sys/types.h>
#include <sys/socket.h>

ssize_t recvfrom(int s, void *buf, size_t len, int flags,


struct sockaddr *from, socklen_t *fromlen);

DESCRIPTION
Lappel systme recvfrom() est utilis pour recevoir des messages.

Si from nest pas NULL, et si le protocole sous-jacent fournit ladresse de la source,

celle-ci y est insre. Largument fromlen est un paramtre rsultat, initialis la


taille du tampon from, et modifi en retour pour indiquer la taille relle de l
adresse enregistre.
...
VALEUR RENVOYE
Ces fonctions renvoient le nombre doctets reus si elles russissent, ou -1 si elles
chouent. La valeur de retour sera 0 si le pair a effectu un arrt normal.
Extrait de la page man de lappel systme recvfrom

C'est l'appel recvfrom() qui remplit la structure sockaddr_in avec les informations du point de com-
munication du client (adresse IPv4 et numro de port pour PF_INET).

TP Dveloppement Rseau n2 : Socket UDP 13 / 20 2012 tv <tvaira@free.fr>


MANIPULATIONS

diter le programme suivant dans un fichier que vous nommerez "serveurUDP.c" :


#include <stdio.h>
#include <stdlib.h> /* pour exit */
#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, htonl et inet_aton */

#define PORT IPPORT_USERRESERVED // = 5000

#define LG_MESSAGE 256

int main()
{
int descripteurSocket;
struct sockaddr_in pointDeRencontreLocal;
struct sockaddr_in pointDeRencontreDistant;
socklen_t longueurAdresse;
char messageRecu[LG_MESSAGE]; /* le message de la couche Application ! */
int lus; /* nb doctets lus */
int retour;

// Cre un socket de communication


descripteurSocket = socket(PF_INET, SOCK_DGRAM, 0);

// Teste la valeur renvoye par lappel systme socket()


if(descripteurSocket < 0) /* chec ? */
{
perror("socket"); // Affiche le message derreur
exit(-1); // On sort en indiquant un code erreur
}
printf("Socket cre avec succs ! (%d)\n", descripteurSocket);

// On prpare ladresse dattachement locale


longueurAdresse = sizeof(struct sockaddr_in);
memset(&pointDeRencontreLocal, 0x00, longueurAdresse);
pointDeRencontreLocal.sin_family = PF_INET;
pointDeRencontreLocal.sin_addr.s_addr = htonl(INADDR_ANY); // nimporte quelle interface
locale disponible
pointDeRencontreLocal.sin_port = htons(PORT); // <- 5000

// On demande lattachement local de la socket


if((bind(descripteurSocket, (struct sockaddr *)&pointDeRencontreLocal, longueurAdresse))
< 0)
{
perror("bind");
exit(-2);
}
printf("Socket attache avec succs !\n");

//<-- Dbut de ltape n4


// Obtient la longueur en octets de la structure sockaddr_in

TP Dveloppement Rseau n2 : Socket UDP 14 / 20 2012 tv <tvaira@free.fr>


MANIPULATIONS

longueurAdresse = sizeof(pointDeRencontreDistant);
// Initialise 0 la structure sockaddr_in (cest lappel recvfrom qui remplira cette
structure)
memset(&pointDeRencontreDistant, 0x00, longueurAdresse);

// Initialise 0 le message
memset(messageRecu, 0x00, LG_MESSAGE*sizeof(char));

// Rceptionne un message du client


lus = recvfrom(descripteurSocket, messageRecu, sizeof(messageRecu), 0, (struct sockaddr
*)&pointDeRencontreDistant, &longueurAdresse);
switch(lus)
{
case -1 : /* une erreur ! */
perror("recvfrom");
close(descripteurSocket);
exit(-3);
case 0 :
fprintf(stderr, "Aucune donne na t reue !\n\n");
close(descripteurSocket);
return 0;
default: /* rception de n octets */
printf("Message %s reu avec succs (%d octets)\n\n", messageRecu, lus);
}
//--> Fin de ltape n4 !

// On ferme la ressource avant de quitter


close(descripteurSocket);

return 0;
}
Un serveur UDP en C

Une simple excution du serveur le place en attente dune rception de donnes :


$ ./serveurUDP
Socket cre avec succs ! (3)
Socket attache avec succs !
^C

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 :
$ ./serveurUDP & ./serveurUDP
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. TCP et UDP ne
partagent pas le mme espace d'adressage (numro de port logique indpendant).

TP Dveloppement Rseau n2 : Socket UDP 15 / 20 2012 tv <tvaira@free.fr>


MANIPULATIONS

Testons notre serveur avec notre client :


$ ./serveurUDP
Socket cre avec succs ! (3)
Socket attache avec succs !
Message Hello world !
reu avec succs (14 octets)

$ ./clientUDP-3
Socket cre avec succs ! (3)
Socket attache avec succs !
Message Hello world !
envoy avec succs (14 octets)

Il est videmment possible de tester notre serveur avec le client UDP de netcat avec l'option -u.

Bilan
Lchange entre un client et un serveur UDP peut tre maintenant schmatis de la manire suivante :

Les appels systmes utiliss dans un change UDP

TP Dveloppement Rseau n2 : Socket UDP 16 / 20 2012 tv <tvaira@free.fr>


TRAVAIL DEMAND

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 1. Quest-ce quune socket ?

Question 2. Quelles sont les trois caractristiques dune socket ?

Question 3. Quelles sont les deux informations qui dfinissent un point de communication en IPv4 ?

Question 4. Comment le serveur connat-il le port utilis par le client ?

Question 5. Comment le client connat-il le port utilis par le serveur ?

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 9. Quel est lordre des octets en rseau ?

Question 10. quels protocoles correspond le domaine PF_INET ? Est-ce le seul utilisable avec linterface
socket ? En citer au moins un autre.

Travail demand

Exercice 1 : client UDP amlior


Lobjectif de cet exercice est de modifier le client UDP afin quil puisse se connecter vers nimporte quel
serveur UDP.
tant donn quun serveur est identifi par une adresse IPv4 (ou par un nom) et un numro de port, il
suffit que le client UDP recoive ces deux informations en arguments comme ceci :
$ ./clientUDP-exo1 adresse_ip_serveur|nom_serveur numero_port_serveur

Si le client ne reoit pas ces deux arguments, il affichera son "usage" :


$ ./clientUDP-exo1
Erreur : argument manquant !
Usage : ./clientUDP-exo1 adresse_ip_serveur|nom_serveur numero_port_serveur

Rappel : rcuprer l'adresse IPv4 en notation dcimale pointe ne pose pas de problme. Par contre, il
vous faudra convertir (avec atoi ou strtol) le numro de port reu sous la forme d'une chane de
caractres en un entier court sur 16 bits avant de l'utiliser.

Question 11. Raliser le client clientUDP-exo1 demand et tester le.

TP Dveloppement Rseau n2 : Socket UDP 17 / 20 2012 tv <tvaira@free.fr>


TRAVAIL DEMAND

Exercice 2 : serveur UDP amlior


Lobjectif de cet exercice est de modifier le serveur UDP afin quil affiche les informations (adresse IPv4
et numro de port) identifiant le client qui lui a envoy des donnes.
Il vous faut utiliser la fonction getnameinfo() pour obtenir ces informations.

Avant on utilisait la fonction gethostbyaddr() mais, celle-ci est maintenant obsolte.

Question 12. Raliser le serveur serveurUDP-exo2 demand et tester le.

Vous devriez obtenir ceci (ici ma machine se nomme "alias") :


$ ./serveurUDP-exo2
Socket cre avec succs ! (3)
Socket attache avec succs !
Message Hello world !
reu du client alias:32941

Rappel : le numro de port du client a t choisi librement (parmi les numros disponibles) par le systme
d'exploitation.

Exercice 3 : une messagerie instantane en UDP


Lobjectif de cet exercice est de raliser un mini-chat multi-clients.

Fonctionnement du mini-chat

TP Dveloppement Rseau n2 : Socket UDP 18 / 20 2012 tv <tvaira@free.fr>


TRAVAIL DEMAND

Le principe est simple : tous les messages envoys au serveur seront distribus lensemble des clients en
ligne. Un client est considr "en ligne" si il a dj envoy un message.
On se limitera :
des messages dune taille de 225 caractres (pour un tampon de 256 cractres max.)
10 clients en ligne maximum

Un protocole plus labor devrait tre mis en oeuvre au niveau de la couche APPLICATION !

Question 13. crire le serveur serveurChat.c.

Voici un exemple de ce que vous devez obtenir ct serveur :


$ ./serveurChat
Socket cre avec succs ! (3)
Socket attache avec succs !

Message : salut !
-> reu du client [192.168.52.3:35256]

Liste des clients en ligne :


[192.168.52.3:35256]

Message : ??
-> reu du client [192.168.52.2:54524]

Message : ??
-> envoy [192.168.52.3:35256]

Le message a t envoy 1 client(s)

Liste des clients en ligne :


[192.168.52.3:35256]
[192.168.52.2:54524]

Message : Bonjour tous !


-> reu du client [192.168.52.1:35639]

Message : Bonjour tous !


-> envoy [192.168.52.3:35256]

Message : Bonjour tous !


-> envoy [192.168.52.2:54524]

Le message a t envoy 2 client(s)

Liste des clients en ligne :


[192.168.52.3:35256]
[192.168.52.2:54524]
[192.168.52.1:35639]

Message : Il y a du monde aujourdhui ;)


-> reu du client [192.168.52.3:35256]

TP Dveloppement Rseau n2 : Socket UDP 19 / 20 2012 tv <tvaira@free.fr>


TRAVAIL DEMAND

Message : Il y a du monde aujourdhui ;)


-> envoy [192.168.52.2:54524]

Message : Il y a du monde aujourdhui ;)


-> envoy [192.168.52.1:35639]

Le message a t envoy 2 client(s)

Liste des clients en ligne :


[192.168.52.3:35256]
[192.168.52.2:54524]
[192.168.52.1:35639]

Le client ralis l'exercice 1 peut tre utilis ici. Sinon, vous pouvez faire vos tests avec netcat.

Voici un exemple dutilisation de 3 clients :


$ nc -u 192.168.52.83 5000
salut !
[192.168.52.2:54524]> ??
[192.168.52.1:35639]> Bonjour tous !
Il y a du monde aujourdhui ;)
Le client 192.168.52.3

$ nc -u 192.168.52.83 5000
??
[192.168.52.1:35639]> Bonjour tous !
[192.168.52.3:35256]> Il y a du monde aujourdhui ;)
Le client 192.168.52.2

$ nc -u 192.168.52.83 5000
Bonjour tous !
[192.168.52.3:35256]> Il y a du monde aujourdhui ;)
Le client 192.168.52.1

TP Dveloppement Rseau n2 : Socket UDP 20 / 20 2012 tv <tvaira@free.fr>