0% ont trouvé ce document utile (0 vote)
50 vues21 pages

Cours Sockets Par6

Ce document présente une introduction aux sockets TCP et UDP, ainsi que leur mise en œuvre en C et Java. Il aborde les concepts de communication entre applications, l'adressage réseau, et les structures de données nécessaires pour manipuler les identifiants de machines. Enfin, il détaille la création et la gestion des sockets, y compris les opérations de liaison, d'envoi et de réception de données.

Transféré par

Khadim Ndiaye Mbaye
Copyright
© © All Rights Reserved
Nous prenons très au sérieux les droits relatifs au contenu. Si vous pensez qu’il s’agit de votre contenu, signalez une atteinte au droit d’auteur ici.
Formats disponibles
Téléchargez aux formats PDF, TXT ou lisez en ligne sur Scribd
0% ont trouvé ce document utile (0 vote)
50 vues21 pages

Cours Sockets Par6

Ce document présente une introduction aux sockets TCP et UDP, ainsi que leur mise en œuvre en C et Java. Il aborde les concepts de communication entre applications, l'adressage réseau, et les structures de données nécessaires pour manipuler les identifiants de machines. Enfin, il détaille la création et la gestion des sockets, y compris les opérations de liaison, d'envoi et de réception de données.

Transféré par

Khadim Ndiaye Mbaye
Copyright
© © All Rights Reserved
Nous prenons très au sérieux les droits relatifs au contenu. Si vous pensez qu’il s’agit de votre contenu, signalez une atteinte au droit d’auteur ici.
Formats disponibles
Téléchargez aux formats PDF, TXT ou lisez en ligne sur Scribd

Systèmes Distribués Plan

1. Présentation générale des sockets


Licence Informatique 3ème année
2. Sockets UDP
3. Sockets TCP
Sockets TCP/UDP et leur
mise en œuvre en C & Java 4. Multicast UDP/IP

Eric Cariou

Université de Pau et des Pays de l'Adour


UFR Sciences Pau – Département Informatique

[Link]@[Link] 1 2

Rappel sur les réseaux Adressage


 TCP ou UDP
 Adressage pour communication entre applications
 Adresse « réseau » application = couple de 2 informations
 Communication entre systèmes aux extrémités
 Adresse IP : identifiant de la machine sur laquelle tourne l'appli
 Pas de visibilité des systèmes intermédiaires
 Numéro de port : identifiant local réseau de l'application
 Couche réseau : adresse IP
Application Application  Ex : [Link]
Communication d’extrémité
 Couche transport : numéro de port TCP ou UDP
à extrémité
 Ce numéro est en entier d'une valeur quelconque
TCP/UDP TCP/UDP  Ports < 1024 : réservés pour les applications ou protocoles systèmes
IP IP IP  Exemple : 80 = HTTP, 21 = FTP, ...
 Sur un port : réception ou envoi de données
Liaison Liaison Liaison
 Adresse notée : @IP:port ou nomMachine:port
Physique Physique Physique  [Link]:80 : accès au serveur Web tournant sur la
3 machine d'adresse IP [Link] 4

Sockets
Sockets
 Socket : prise
 Associée, liée localement à un port
 C'est un point d'accès aux couches réseaux
 Services d'émission et de réception de données sur la
socket via le port
 En mode connecté (TCP)
 Connexion = tuyau entre 2 applications distantes
 Une socket est un des deux bouts du tuyau
 Chaque application a une socket locale pour gérer la  Une socket est
communication à distance
 Un point d'accès aux couches réseau TCP/UDP
 Une socket peut-être liée
 Liée localement à un port
 Sur un port précis à la demande du programme
 Adressage de l'application sur le réseau : son couple @IP:port
 Sur un port quelconque libre déterminé par le système
 Elle permet la communication avec un port distant sur une
 Par défaut, on ne peut lier qu'une socket par port 5 6
machine distante : c'est-à-dire avec une application distante
Client/serveur avec sockets
 Il y a toujours différenciation entre une partie client
et une partie serveur
 Deux rôles distincts au niveau de la communication via
TCP/UDP
 Mais possibilité que les éléments communiquant jouent
un autre rôle ou les 2 en même temps Sockets UDP
 Différenciation pour plusieurs raisons
 Identification : on doit connaître précisément la
localisation d'un des 2 éléments communicants
 Le coté serveur communique via une socket liée à un port
précis : port d'écoute
 L'adresse du serveur (@IP et port) est connue du client
 Dissymétrie de la communication/connexion
7 8
 Le client initie la connexion ou la communication

Sockets UDP : principe Sockets UDP : principe


 Mode datagramme
 Principe de communication
 Envois de paquets de données (datagrammes)  La partie serveur crée une socket et la lie à un port UDP
particulier
 Pas de connexion entre parties client et serveur
 La partie client crée une socket pour accéder à la
 Pas de fiabilité ou de gestion de la communication couche UDP et la lie sur un port quelconque
 Un paquet peut ne pas arriver en étant perdu par le réseau et  Le serveur se met en attente de réception de paquet sur
sans que l'émetteur en soit informé
sa socket
 Un paquet P2 envoyé après un paquet P1 peut arriver avant ce
paquet P1 (selon la gestion des routes dans le réseau)  Le client envoie un paquet via sa socket en précisant
 Un paquet envoyé à un destinataire non prêt à en recevoir (pas l'adresse du destinataire : couple @IP/port de la partie
de socket sur le port) est détruit sans en informer l'émetteur serveur
 Caractéristiques des primitives de communication  @IP de la machine sur laquelle tourne la partie serveur et
numéro de port sur lequel est liée la socket de la partie serveur
 Émission de paquets est non bloquante  Il est reçu par le serveur (sauf si problème réseau)
 Réception de paquets est bloquante (sauf s'il y  L'adresse du client (@IP et port) est précisée dans
9 10
avait des paquets non lus) le paquet, le serveur peut alors lui répondre
Structures de données C
 Ensemble de structures de données pour
manipulation des adresses des machines, des
identifications réseau ...
 Adresse IP (v4) d'une machine
Sockets UDP en C  Fichier <netinet/in.h>
 typedef uint32_t in_addr_t;
struct in_addr {
in_addr_t s_addr;
};
 Les 4 octets d'une adresse IP sont codés par un
entier non signé sur 32 bits
 Ex. : [Link] correspond à l'entier 0xC0A80C28

11 12
Conversions adresse IP Structures de données C
 Fichier <arpa/inet.h>
 Identifiants d'une machine
 Fichier <netdb.h>
 Codage in_addr vers chaine de type ''X.X.X.X''
 struct hostent {
 char *inet_ntoa(struct in_addr adresse) char *h_name; nom officiel,
 Renvoie une chaîne statique char **h_aliases; liste des alias,
 Codage chaîne ''X.X.X.X'' vers in_addr ou long int h_addrtype; type d'adresse,
int h_length; longueur de l'adresse,
 int inet_aton(const char *chaine, char **h_addr_list; liste des adresses
struct in_addr *adresse) #define h_addr h_addr_list[0] première
unsigned long inet_addr(char *chaine) adresse
 inet_aton pas disponible sur tous systèmes };
 inet_addr fonction standard  Type d'adresse : internet (IP v4) par défaut
 Retourne valeur INADDR_NONE en cas d'erreur  Valeur = AF_INET, longueur = 4 (en octets)
 Attention : INADDR_NONE correspond aussi à une adresse de
13  Une machine peut avoir plusieurs adresses IP et noms14
broadcast ([Link])

Accès identifiants machines Accès identifiants machines


 Accès aux identifiants de machines distantes
 Accès aux identifiants locaux d'une machine
 Définitions dans fichier <netdb.h>
 Définition dans fichier <unistd.h>
 struct hostent *gethostbyname(char *nom)
 int gethostname(char *nom, size_t lg)  Retourne l'identifiant de la machine dont le nom est passé en
 Récupère le (premier) nom de la machine locale, placé dans paramètre ou NULL si aucune machine de ce nom trouvée
nom  Recherche des infos dans l'ordre suivant
 lg est la taille de l'espace mémoire référencé par nom 1. Serveur de nom DNS
 Retourne 0 si appel réussi, -1 sinon 2. Serveur NIS
 long gethostid() 3. Fichier local /etc/hosts
 Retourne l'adresse IP de la machine locale sous forme d'un  Note
entier sur 4 octets  La structure retournée est placée à une adresse statique en mémoire
 Un nouvel appel de gethostbyname écrase la valeur à cette
adresse
 Nécessité de copier la structure avec un memcopy ou un bcopy
15 si on veut la conserver 16

Accès identifiants machines Identifiants d'une socket


 Accès identifiants machines distantes (suite)
 Identifiants d'une socket
 struct hostent *gethostbyaddr(  Couple adresse IP/numéro de port dans le contexte IP
char *adresse, zone mémoire contenant  Identifiant « général » abstrait
l'adresse de la machine,
 struct sockaddr
int longueur, longeur de l'adresse,
int type) type de l'adresse  On ne l'utilise jamais directement mais une spécialisation
selon le type de réseau ou de communication utilisé
 Retourne les identifiants d'une machine à partir de son adresse
 Exemples de spécialisation
 Retourne NULL si machine non trouvée
 Si adresse IP
 Fichier <netinet/in.h>
 longueur = 4
 struct sockaddr_in
 type = AF_INET  Contexte IP
 adresse pointe vers une entier sur 4 octets codant l'adresse IP  Fichier <sys/un.h>
 Note  struct sockaddr_un
 Là aussi, retourne une référence sur une zone mémoire statique  Contexte Unix (communication locale à la même machine via
écrasée à chaque nouvel appel 17 des sockets) 18
Identifiants d'une socket Création et gestion de sockets
 Création d'une socket
 Identifiants socket TCP/UDP – IP
 int socket(int domaine, int type, int protocole)
 struct sockaddr_in {
short sin_familly; = AF_INET,
 Retourne un descripteur correspondant à la socket créée
u_short sin_port; port associée à la socket,  Similaire à un descripteur de fichier
struct in_addr sin_adr; adresse de la machine,  Paramètres
char sin_zero[8]; champ de 0 pour compléter  Domaine : utilisation de constantes parmi
};  AF_UNIX : domaine local Unix
 AF_INET : domaine IP
 Opérations sur les sockets  Type : type de la socket selon protocoles sous-jacents, constantes
parmi entre autres
 Fichier <sys/socket.h>  SOCK_DGRAM : socket mode datagramme, non connecté et non fiable
(UDP par défaut)
 Création de sockets
 SOCK_STREAM : socket mode connecté et fiable (TCP par défaut)
 Liaison sur un port local  SOCK_RAW : socket bas niveau (IP ou ICMP)
 Envoi/réception de données  Protocole
 ...
 On utilise généralement la valeur 0 qui sélectionne le protocole par défaut
19 associé à chaque type de socket 20

Création et gestion de sockets Création et gestion de sockets


 Liaison d'une socket sur un port particulier
 Création d'une socket (suite)  int bind(int sock_desc, descripteur de la socket,
 En cas d'erreur lors de la création : retourne -1 struct sockaddr *adresse, adresse sur laquelle
lier la socket,
 Pour connaître le détail de l'erreur socklen_t longueur_adresse) taille de l'adresse (int)
 Consulter la valeur de la variable errno ou afficher un  Retourne -1 en cas de problème
message avec la fonction perror  Problèmes les plus courants
 Liste des erreurs dans le fichier <ernno.h>  Le port choisi a déjà une socket liée dessus (erreur EADDRINUSE)
 Si la socket n'est pas liée à un port donné via un bind  Liaison non autorisée (ex : port < 1024) sur ce port (erreur EACCES)
 Déclaration typique d'une adresse
 Lors du premier envoi d'un paquet, elle sera liée localement à  De type sockaddr_in pour IP, avec champs positionnés comme suit
un port quelconque disponible
 sin_family = AF_INET
 Fermeture d'une socket  sin_addr.s_addr = INADDR_ANY (ou une adresse IP locale)
 INADDR_ANY : permet d'utiliser n'importe quelle IP de la machine si elle
 int close(int socket_desc) en a plusieurs et/ou évite de connaître l'adresse IP locale
 sin_port = port sur lequel on veut lier la socket
 Ferme la socket dont le descripteur est passé en paramètre
 Si 0 : n'importe quel port libre
21 22

Représentations des nombres


Création et gestion de sockets  Selon le système/matériel, le codage binaire des nombres
 Récupérer les informations sur une socket peut changer
 int getsockname(  Big Endian : octet de poids fort à gauche
int descripteur, descripteur de la socket,  Little Endian : octet de poids fort à droite
struct sockaddr *adresse, contiendra l'adresse
 Pour éviter une mauvaise interprétation des nombres
mémoire de l'adresse réseau
int *longueur_adresse)  On les code en « mode réseau » lorsqu'on les utilise dans les

 Paramètre longueur_adresse
structures ou fonctions d'accès au réseau et sockets
 A l'appel : taille de l'espace réservé pour contenir l'adresse  4 opérations assurent la traduction « mode réseau / local »
 Au retour : longueur effective de l'adresse  u_short htons(u_short) : entier court local vers réseau
 u_long htonl(u_long) : entier long local vers réseau
 u_short ntohs(u_short) : entier court réseau vers local
 u_long ntohl(u_long) : entier long réseau vers local
 Entiers courts : numéros de port
23  Entiers longs : adresses IP 24
Envoi/réception données en UDP Envoi/réception données en UDP
 Envoi de données sur socket  Réception de données
 int sendto(  int recvfrom(
int descripteur, descripteur de la socket qui int descripteur, descripteur de la socket qui
émettra les données, attend les données,
void *message, pointeur vers la zone de void *message, pointeur vers la zone de
données à émettre, données,
int longueur, longueur des données, int longueur, taille max de la zone données,
int option, 0, int option, 0 ou MSG_PEEK,
struct sockaddr *adresse, adresse de la socket struct sockaddr *adresse, adresse de la socket
destinatrice, émettrice,
int longueur_adresse) longueur de l'adresse int *longueur_adresse) longueur de l'adresse
 Globalement, deux types d'informations à passer en paramètre
 Paramètres à fournir
Lien vers les données à émettre

 L'adresse identifiant le destinataire (couple @IP/port)
 Lien et taille de la zone de données qui contiendra les données
reçues
 Retourne
 longueur_adresse : longueur de l'adresse, à initialiser à
 Nombre de caractères (réellement) envoyés
25 l'appel, sera modifiée (avec la même valeur …) au retour 26
 -1 en cas de problème (détails avec perror ou errno)

Envoi/réception données en UDP Envoi/réception données en UDP


 Réception de données (suite)  Notes sur les tailles des données envoyées/reçues
 recvfrom retourne  A priori pas limite en taille pour les données circulant
 Le nombre de caractères reçus dans les paquets UDP, mais
 -1 en cas de problème  Pour tenir dans un seul datagramme IP, le datagramme UDP ne
doit pas contenir plus de 65467 octets de données
 En retour via les pointeurs  Un datagramme UDP est rarement envoyé via plusieurs
 Zone de données initialisée avec les données datagrammes IP
 Adresse : contient l'adresse de la socket émettrice  Mais en pratique : il est conseillé de ne pas dépasser 8176 octets
(longueur_adresse contient la taille de cette adresse)  Car la plupart des systèmes limitent à 8 Ko la taille des
datagrammes UDP
 Paramètre option = MSG_PEEK
 Pour être certain de ne pas perdre de données : 512 octets max
 Le paquet de données reçu n'est pas retiré du tampon  Si datagramme UDP trop grand : les données sont tronquées
 A la prochaine réception de données, on lira les mêmes
données  Si la taille de la zone de données en réception est plus
petite que les données envoyées
 Réception de données est bloquante par défaut
27  Les données reçues sont généralement tronquées 28
 Sauf si des paquets avaient été reçus et pas encore lus

Exemple de programme UDP Exemple UDP : coté client


 #include <stdio.h>
 Client / serveur basique en UDP #include <stdlib.h>
#include <unistd.h>
 Client envoie une chaîne « bonjour » au serveur et #include <sys/types.h>
attend une réponse #include <netdb.h>
#include <sys/socket.h>
 Serveur se met en attente de réception de données et #include <netinet/in.h>
renvoie la chaîne « bien recu » à l'émetteur #include <errno.h>

 Identification du serveur #define TAILLEBUF 20


 Lancé sur la machine scinfe122 int main() {
 Écoute sur le port 4000
// identifiant de la machine serveur
struct hostent *serveur_host;
// adresse de la socket coté serveur
static struct sockaddr_in addr_serveur;
// taille de l'addresse socket
29 socklen_t lg; 30
Exemple UDP : coté client (suite) Exemple UDP : coté client (suite)
 // descripteur de la socket locale  // récupération identifiant du serveur
int sock; serveur_host = gethostbyname("scinfe122");
// chaine à envoyer if (serveur_host==NULL) {
char *msg = "bonjour"; perror("erreur adresse serveur");
// buffer de réception exit(1);
char buffer[TAILLEBUF]; }
// chaine reçue en réponse
char *reponse; // création adresse socket destinatrice
// nombre d'octets lus ou envoyés bzero(&addr_serveur, sizeof(struct sockaddr_in));
int nb_octets; addr_serveur.sin_family = AF_INET;
addr_serveur.sin_port = htons(4000);
// création d'une socket UDP memcpy(&addr_serveur.sin_addr.s_addr,
sock = socket(AF_INET, SOCK_DGRAM, 0); serveur_host -> h_addr, serveur_host -> h_length);
if (sock == -1) {
perror("erreur création socket");
exit(1);
}
31 32

Exemple UDP : coté client (fin) Exemple UDP : coté serveur


 // on envoie le message "bonjour" au serveur
lg = sizeof(struct sockaddr_in);  // adresse de la socket locale
nb_octets = sendto(sock, msg, strlen(msg)+1, 0, static struct sockaddr_in addr_local;
(struct sockaddr*)&addr_serveur, lg); // adresse de la socket coté serveur
if (nb_octets == -1) { static struct sockaddr_in addr_client;
perror("erreur envoi message");
// identifiant du client
exit(1); }
printf("paquet envoyé, nb_octets = %d\n",nb_octets);
struct hostent *host_client;
// taille de l'addresse socket
// on attend la réponse du serveur socklen_t lg;
nb_octets = recvfrom(sock, buffer, TAILLEBUF, 0, // descripteur de la socket locale
(struct sockaddr*)&addr_serveur, &lg); int sock;
if (nb_octets == -1) { // chaine à envoyer en réponse
perror("erreur réponse serveur"); char *reponse = "bien recu";
exit(1); } // buffer de réception
reponse = (char *)malloc(nb_octets * sizeof(char)); char buffer[TAILLEBUF];
memcpy(reponse, buffer, nb_octets);
printf("reponse recue du serveur : %s\n",reponse); // chaine reçue
char *chaine;
// on ferme la socket // nombre d'octets lus ou envoyés
close(sock); int nb_octets;
} 33 34

Exemple UDP : coté serveur (suite) Exemple UDP : coté serveur (suite)
 // création de la socket  // attente de données venant d'un client
sock = socket(AF_INET, SOCK_DGRAM, 0); lg = sizeof(struct sockaddr_in);
if (sock == -1) { nb_octets = recvfrom(sock, buffer, TAILLEBUF, 0,
perror("erreur création socket"); (struct sockaddr *)&addr_client, &lg);
exit(1); if (nb_octets == -1) {
} perror("erreur réception paquet");
exit(1);
// liaison de la socket sur le port local 4000 }
bzero(&addr_local, sizeof(struct sockaddr_in));
addr_local.sin_family = AF_INET; // récupère nom de la machine émettrice des données
addr_local.sin_port = htons(4000); host_client = gethostbyaddr(&(addr_client.sin_addr),
addr_local.sin_addr.s_addr=htonl(INADDR_ANY); sizeof(long), AF_INET);
if (host_client == NULL) {
if( bind(sock, (struct sockaddr*)&addr_local, perror("erreur gethostbyaddr");
sizeof(addr_local))== -1 ) { exit(1);
perror("erreur bind"); }
exit(1);
} 35 36
Exemple UDP : coté serveur (fin) Notes sur ces exemples UDP
 Variables de type sockaddr_in
 // affichage message reçu et coordonnées émetteur  A déclarer en static
chaine = (char *)malloc(nb_octets * sizeof(char));
memcpy(chaine, buffer, nb_octets);  Fonctions de copies zones mémoire
printf("recu message %s de la part de %s
 memcpy(void *dest, void *source, size_t lg);
sur le port %d\n", chaine, host_client->h_name,
ntohs(addr_client.sin_port));
memmove(void *dest, void *source, size_t lg);
 Copie lg octets d'une zone mémoire source vers une zone
// envoi de la réponse à l'émetteur mémoire destination
nb_octets = sendto(sock, reponse, strlen(reponse)+1,  memmove : à utiliser pour des copies de zones mémoires se
0,(struct sockaddr*)&addr_client, lg);
if (nb_octets == -1) { recouvrant partiellement
perror("erreur envoi réponse");  Initialisation de zone mémoire
exit(1);
}  memset(void *zone_mem, int valeur, size_t lg)
 Initialise chacun des lg premiers octets de la zone avec valeur
// fermeture la socket  bzero(void *zone_mem, size_t lg)
close(sock);
} 37  Initialise les lg premiers octets de la zone à 0 38

Sockets UDP en Java


 Sockets UDP en Java
 Pas de différences fondamentales de fonctionnement
par rapport à leur utilisation en C
 Caractéristiques identiques
Sockets UDP en Java  Mode non connecté, communication par datagramme
 Pas de gestion de la taille des données envoyées
 Possibilité de perte de données à l'émission et réception

39 40

Sockets UDP en Java Codage adresse IP


 Classe InetAddress
 Java intègre nativement les fonctionnalités de
 Constructeurs
communication réseau au dessus de TCP-UDP/IP
 Pas de constructeurs, on passe par des méthodes statiques
 Package [Link] pour créer un objet
 Classes utilisées pour communication via UDP  Méthodes
 public static InetAddress getByName(String host)
 InetAddress : codage des adresses IP throws UnknownHostException
 DatagramSocket : socket mode non connecté (UDP)  Crée un objet InetAddress identifiant une machine dont le nom
est passé en paramètre
 DatagramPacket : paquet de données envoyé via une  L'exception est levée si le service de nom (DNS...) du système ne
socket sans connexion (UDP) trouve pas de machine du nom passé en paramètre sur le réseau
 Si précise une adresse IP sous forme de chaîne (''[Link]'')
au lieu de son nom, le service de nom n'est pas utilisé
 Une autre méthode permet de préciser l'adresse IP sous forme d'un
tableau de 4 octets
41 42
Codage adresse IP Datagramme
 Classe InetAddress  Classe DatagramPacket
 Méthodes (suite)  Structure des données en mode datagramme
 public static InetAddress getLocalHost()  Constructeurs
throws UnknownHostException
 public DatagramPacket(byte[] buf, int length)
 Retourne l'adresse IP de la machine sur laquelle tourne le
programme, c'est-à-dire l'adresse IP locale
 Création d'un paquet pour recevoir des données (sous forme d'un
tableau d'octets)
 public String getHostName()
 Les données reçues seront placées dans buf
 Retourne le nom de la machine dont l'adresse est codée par  length précise la taille max de données à lire
l'objet InetAddress
 Ne pas préciser une taille plus grande que celle du tableau
 En général, length = taille de buf
 Variante du constructeur : avec un offset pour ne pas commencer
au début du tableau

43 44

Datagramme Datagramme
 Classe DatagramPacket  Classe DatagramPacket
 Constructeurs (suite)  Méthodes « get »
 public DatagramPacket(byte[] buf, int length,  InetAddress getAddress()
InetAddress address, int port)  Si paquet à envoyer : adresse de la machine destinataire
 Création d'un paquet pour envoyer des données (sous forme d'un  Si paquet reçu : adresse de la machine qui a envoyé le paquet
tableau d'octets)  int getPort()
 buf : contient les données à envoyer  Si paquet à envoyer : port destinataire sur la machine distante
 length : longueur des données à envoyer  Si paquet reçu : port utilisé par le programme distant pour envoyer
 Ne pas préciser une taille supérieure à celle de buf le paquet
 address : adresse IP de la machine destinataire des données  byte[] getData
 port : numéro de port distant (sur la machine destinataire) où  Données contenues dans le paquet
envoyer les données  int getLength()
 Si paquet à envoyer : longueur des données à envoyer
 Si paquet reçu : longueur des données reçues
45 46

Datagramme Sockets mode datagramme (UDP)


 Classe DatagramPacket  Classe DatagramSocket
 Méthodes « set »  Socket en mode datagramme
 void setAddress(InetAdress adr)
 Constructeurs
 Positionne l'adresse IP de la machine destinataire du paquet
 void setPort(int port)  public DatagramSocket() throws SocketException
 Positionne le port destinataire du paquet pour la machine distante
 Crée une nouvelle socket en la liant à un port quelconque libre
 void setData(byte[] data)  Exception levée en cas de problème (a priori il ne doit pas y en
avoir)
 Positionne les données à envoyer  public DatagramSocket(int port)
 int setLength(int length) throws SocketException
 Positionne la longueur des données à envoyer  Crée une nouvelle socket en la liant au port local précisé par le
paramètre port
 Exception levée en cas de problème : notamment quand le port est
déjà occupé

47 48
Sockets mode datagramme (UDP) Sockets mode datagramme (UDP)
 Classe DatagramSocket  Classe DatagramSocket
 Méthodes d'émission/réception de paquet  Autres méthodes
 public void send(DatagramPacket p)  public void close()
throws IOException
 Ferme la socket et libère le port à laquelle elle était liée
 Envoie le paquet passé en paramètre. Le destinataire est identifié par le
couple @IP/port précisé dans le paquet
 public int getLocalPort()
 Exception levée en cas de problème d'entrée/sortie  Retourne le port local sur lequel est liée la socket
 public void receive(DatagramPacket p)  Possibilité de créer un canal (mais toujours en mode
throws IOException non connecté)
 Reçoit un paquet de données
 Pour restreindre la communication avec un seul destinataire
 Bloquant tant qu'un paquet n'est pas reçu
distant
 Quand paquet arrive, les attributs de p sont modifiés
 Les données reçues sont copiées dans le tableau passé en paramètre
 Car par défaut peut recevoir sur la socket des paquets venant
lors de la création de p et sa longueur est positionnée avec la taille des de n'importe où
données reçues
 Les attributs d'@IP et de port de p contiennent l'@IP et le port de la
socket distante qui a émis le paquet 49 50

Sockets mode datagramme (UDP) Sockets UDP Java – exemple coté client
 Classe DatagramSocket  InetAddress adr;
DatagramPacket packet;
 Réception de données : via méthode receive DatagramSocket socket;
 Méthode bloquante sans contrainte de temps : peut rester en // adr contient l'@IP de la partie serveur
attente indéfiniment si aucun paquet n'est jamais reçu adr = [Link]("scinfr222");
 Possibilité de préciser un délai maximum d'attente // données à envoyer : chaîne de caractères
 public void setSoTimeout(int timeout) byte[] data = (new String("youpi")).getBytes();
throws SocketException
// création du paquet avec les données et en précisant l'adresse du serveur
 L'appel de la méthode receive sera bloquante pendant au // (@IP et port sur lequel il écoute : 7777)
plus timeout millisecondes packet = new DatagramPacket(data, [Link], adr, 7777);
 Une méthode receive se terminera alors de 2 façons
// création d'une socket, sans la lier à un port particulier
 Elle retourne normalement si un paquet est reçu en moins du temps socket = new DatagramSocket();
positionné par l'appel de setSoTimeout
 L'exception SocketTimeoutException est levée pour indiquer que le // envoi du paquet via la socket
délai s'est écoulé avant qu'un paquet ne soit reçu [Link](packet);
 SocketTimeoutException est une sous-classe de 51 52
IOException

Sockets UDP Java – exemple coté serveur Sockets UDP en Java – exemple suite
 DatagramSocket socket;
DatagramPacket packet;
 La communication se fait souvent dans les 2 sens
// création d'une socket liée au port 7777
 Le serveur doit donc connaître la localisation du client
DatagramSocket socket = new DatagramSocket(7777);  Elle est précisée dans le paquet qu'il reçoit du client
// tableau de 15 octets qui contiendra les données reçues  Réponse au client, coté serveur
byte[] data = new byte[15];
 [Link](" ca vient de : "+
// création d'un paquet en utilisant le tableau d'octets [Link]()+":"+ [Link]());
packet = new DatagramPacket(data, [Link]);
// on met une nouvelle donnée dans le paquet
// attente de la réception d'un paquet. Le paquet reçu est placé dans // (qui contient donc le couple @IP/port de la socket coté client)
// packet et ses données dans data. String reponse = "bien recu";
[Link](packet); [Link]([Link]());
[Link]([Link]());
// récupération et affichage des données (une chaîne de caractères)
String chaine = new String([Link](), 0,
[Link]());
// on envoie le paquet au client
[Link](" recu : "+chaine); [Link](packet);
53 54
Sockets UDP en Java – exemple suite Critique sockets UDP
 Réception réponse du serveur, coté client  Avantages
// attente paquet envoyé sur la socket du client  Simple à programmer (et à appréhender)
[Link](packet);
 Inconvénients
// récupération et affichage de la donnée contenue dans le paquet  Pas fiable
String chaine = new String([Link](), 0,
[Link]());  Ne permet d'envoyer que des tableaux de byte
[Link](" recu du serveur : "+chaine);  Si en C cela convient parfaitement au niveau de la manipulation
de données, en Java, c'est de l'information de bas niveau non
naturelle
 En Java, il faut pouvoir envoyer des objets quelconques via des
sockets

55 56

Structure des données échangées Conversion Object <-> byte[]


 Format des données à transmettre  Pour émettre et recevoir n'importe quel objet via des
sockets UDP
 Très limité a priori : tableaux de byte
 En écriture : conversion de Object en byte[ ]
 Et attention à la taille réservée : si le récepteur réserve un
public byte[] fromObjectToByte(Object obj) {
tableau trop petit par rapport à celui envoyé, une partie des
ByteArrayOutputStream byteStream =
données est perdue new ByteArrayOutputStream();
 Doit donc pouvoir convertir ObjectOutputStream objectStream =
new ObjectOutputStream(byteStream);
 Un objet quelconque en byte[] pour l'envoyer [Link](obj);
 Un byte[] en un objet d'un certain type après réception return [Link]();
}
 Deux solutions  En lecture : conversion de byte[ ] en Object
 Dans chaque classe à transmettre : rajouter des méthodes qui public Object fromByteToObject(byte[] byteArray) {
font la conversion ByteArrayInputStream byteStream =
 Lourd et dommage de faire des tâches de si « bas-niveau » avec new ByteArrayInputStream(byteArray);
un langage évolué comme Java ObjectInputStream objectStream =
new ObjectInputStream(byteStream);
 Utiliser les flux Java pour conversion automatique return [Link]();
57 58
}

Sockets TCP : principe


 Fonctionnement en mode connecté
 Phase de connexion explicite entre client et serveur avant comm.
 Données envoyées dans un « tuyau » et non pas par paquets
 Flux (virtuels) de données
 Fiable : la couche TCP assure que
 Les données envoyées sont toutes reçues par la machine destinataire
Sockets TCP  Les données sont reçues dans l'ordre où elles ont été envoyées

59 60
Sockets TCP : principe Sockets TCP : résumé communication
 Principe de communication
 Le serveur lie une socket dite d'écoute sur un certain port
bien précis et appelle un service d'attente de connexion
de la part d'un client
 Le client crée une socket liée à un port quelconque puis
appelle un service pour ouvrir une connexion avec le
serveur sur sa socket d'écoute
 Du coté du serveur, le service d'attente de connexion
retourne une socket de service (associée à un port
quelconque)
 C'est la socket qui permet de dialoguer avec ce client
 Il y a une socket de service par client connecté
 Comme avec sockets UDP : le client et le serveur
communiquent en envoyant et recevant des données
via leur socket 61 62

Socket TCP : mise en oeuvre en C


 Utilise les mêmes bases que pour UDP
 Codage des différents identifiants
 Structures sockaddr_in, hostent, in_addr et fonctions associées
 Gestion des sockets : socket() et descripteur de fichier
 Besoin supplémentaire par rapport à UDP
Sockets TCP en C  Fonctions pour attendre des connexions côté serveur
 Fonction pour se connecter à la socket d'écoute du serveur coté
client
 Communication entre client/serveur après phase de
connexion
 Pas besoin de préciser identifiants du coté client à chaque envoi
de données car on fonctionne en mode connecté
 Pas d'usage de recvfrom() et sendto()
 Utilise alors les fonctions système read() et write()
63 64

Sockets TCP : attente connexion Sockets TCP : init. connexion


 Coté serveur  Coté serveur
 Fonction qui attend la connexion d'un client sur une  Fonction pour configurer le nombre maximum de
socket d'écoute connexions pendantes
 Fichier <sys/socket.h>  Nombre maximum de connexions en attente d'un accept à un
 int accept(int socket_ecoute, instant donné (une fois atteint, les suivantes seront rejetées)
struct sockaddr *addr_client,  int listen(int descripteur,
int *lg_addr); int nb_con_pendantes);
 Paramètres  Paramètres
 socket_ecoute : la socket d'écoute (à lier sur un port précis)  descripteur : descripteur de la socket d'écoute à configurer
 addr_client : contiendra l’adresse du client qui se connectera  nb_con_pendantes : nombre max de connexions pendantes autorisées
 lg_addr : contiendra la taille de la structure d’adresse
 A initialiser avant d'appeler la fonction comme pour recvfrom
 Retourne 0 si exécution correcte, -1 en cas de problème
 Retourne un descripteur de socket  Le nombre de connexion pendantes précisé doit être inférieur à la
 La socket de service qui permet de communiquer avec le client qui vient valeur de la constante SOMAXCONN (fichier <sys/socket.h>)
de se connecter  Cette valeur dépend des systèmes d'exploitation
 Retourne -1 en cas d'erreur  SOMAXCONN = 128 sous Linux
 Fonction bloquante jusqu'à l'arrivée d'une demande de connexion65 66
 Fonction à appeler avant de faire les accept
Sockets TCP : ouverture connexion Sockets TCP : envoi/réception données
 Coté client  Si connexion établie
 Fonction pour ouvrir une connexion avec la partie  « tuyau » de communication directe entre socket coté
serveur client et socket de service coté serveur
 int connect(int descripteur,  Pas besoin de préciser l'adresse du destinataire à chaque
struct sockaddr *addr_serveur, envoi de données ni de vérifier l'émetteur à la réception
int lg_addr);
 Paramètres
 Fonctions de communication
 descripteur : descripteur de la socket coté client  On peut utiliser les fonctions standards pour
 addr_serveur : identifiant de la socket d'écoute coté serveur communiquer
 lg_adresse : taille de l'adresse utilisée  write pour émission
 Retourne 0 si tout se passe bien, -1 sinon  read pour réception
 Fonction bloquante
 Si on veut gérer quelques options, fonctions spécialisées
 Si le serveur ne fait pas l'accept de son coté
 send pour émission
67  recv pour réception 68

Sockets TCP : émission Sockets TCP : réception


 2 fonctions (bloquantes) pour réception de données
 2 fonctions pour l'émission de données
 ssize_t read(int descripteur,
 ssize_t write(int descripteur, void *ptr_mem,
void *ptr_mem, size_t longueur);
size_t longueur);
 ssize_t recv(int descripteur,
 ssize_t send(int descripteur, void *ptr_mem,
void *ptr_mem, size_t longueur,
size_t longueur, int option);
int option);  Paramètres
 Paramètres  descripteur : descripteur de la socket
 descripteur : descripteur de la socket  ptr_mem : zone mémoire où seront écrites les données reçues
 ptr_mem : zone mémoire où sont les données à envoyer  longueur : taille de la zone mémoire
 longeur : nombre d'octets à envoyer  option : 3 valeurs possibles que l'on peut combiner (avec des ||)
 0 : réception normale
 option : 0 si envoi normal ou MSG_OOB si envoi de données
 MSG_OOB : réception de données prioritaires
prioritaires
 MSG_PEEK : lecture des données reçues mais sans les retirer du tampon
 Retourne le nombre d'octets écrits ou -1 en cas de pb 69  Retourne le nombre d'octets reçus ou -1 en cas de pb 70

Sockets TCP : exemple Exemple TCP : coté client


 // identification socket d'écoute du serveur
 Même exemple que pour UDP static struct sockaddr_in addr_serveur;
// identifiants de la machine où tourne le serveur
 Serveur attend la connexion du client struct hostent *host_serveur;
 Client envoie une chaîne au serveur // socket locale coté client
int sock;
 Serveur lui répond en lui renvoyant une chaîne // message à envoyer au serveur
char *message = "bonjour";
 Identification du serveur // chaîne où sera écrit le message reçu
char reponse[TAILLEBUF];
 Lancé sur la machine scinfe122 // nombre d'octets envoyés/reçus
 Écoute sur le port 4000 int nb_octets;

// création socket TCP


sock = socket(AF_INET, SOCK_STREAM, 0);
if (sock == -1) {
perror("creation socket");
exit(1); }
71 72
Exemple TCP : coté client (suite) Exemple TCP : coté client (fin)
 // récupération identifiants de la machine serveur  // connexion de la socket client locale à la socket coté serveur
host_serveur = gethostbyname("scinfe122"); if (connect(sock,
if (host_serveur==NULL) { (struct sockaddr *)&addr_serveur,
perror("erreur récupération adresse serveur\n"); sizeof(struct sockaddr_in)) == -1) {
exit(1); perror("erreur connexion serveur");
} exit(1);
}
// création de l'identifiant de la socket d'écoute du serveur
bzero((char *) &addr_serveur, // connexion etablie, on envoie le message
sizeof(addr_serveur)); nb_octets = write(sock, message, strlen(message)+1);
addr_serveur.sin_family = AF_INET;
addr_serveur.sin_port = htons(4000); // on attend la réponse du serveur
memcpy(&addr_serveur.sin_addr.s_addr, nb_octets = read(sock, reponse, TAILLEBUF);
host_serveur->h_addr, host_serveur->h_length); printf(" reponse recue : %s\n", reponse);

// on ferme la socket
close(sock);
73 74

Exemple TCP : coté serveur Exemple TCP : coté serveur (suite)


 // création socket TCP d'écoute
 // adresse socket coté client socket_ecoute = socket(AF_INET, SOCK_STREAM, 0);
static struct sockaddr_in addr_client; if (socket_ecoute == -1) {
// adresse socket locale perror("creation socket");
static struct sockaddr_in addr_serveur; exit(1); }
// longueur adresse
int lg_addr; // liaison de la socket d'écoute sur le port 4000
// socket d'écoute et de service bzero((char *) &addr_serveur, sizeof(addr_serveur));
int socket_ecoute, socket_service; addr_serveur.sin_family = AF_INET;
// buffer qui contiendra le message reçu addr_serveur.sin_port = htons(4000);
char message[TAILLEBUF]; addr_serveur.sin_addr.s_addr=htonl(INADDR_ANY);
// chaîne reçue du client if( bind(socket_ecoute,
char *chaine_recue; (struct sockaddr*)&addr_serveur,
// chaîne renvoyée au client sizeof(addr_serveur))== -1 ) {
char *reponse = "bien recu"; perror("erreur bind socket écoute");
// nombre d'octets reçus ou envoyés exit(1);
int nb_octets; }
75 76

Exemple TCP : coté serveur (suite) Exemple TCP : coté serveur (fin)
 // configuration socket écoute : 5 connexions max en attente  // la connexion est établie, on attend les données envoyées par le client
if (listen(socket_ecoute, 5) == -1) { nb_octets = read(socket_service, message,
perror("erreur listen"); TAILLEBUF);
exit(1); // affichage du message reçu
} chaine_recue =
(char *)malloc(nb_octets * sizeof(char));
// on attend la connexion du client memcpy(chaine_recue, message, nb_octets);
lg_addr = sizeof(struct sockaddr_in); printf("recu message %s\n", chaine_recue);
socket_service = accept(socket_ecoute,
(struct sockaddr *)&addr_client, // on envoie la réponse au client
&lg_addr); write(socket_service, reponse, strlen(reponse)+1);
if (socket_service == -1) {
perror("erreur accept"); // on ferme les sockets
exit(1); close(socket_service);
} close(socket_ecoute);

77 78
Sockets TCP : gestion données Pseudo-connexion en UDP
 En UDP : mode datagramme
 Peut utiliser la primitive connect en UDP
 Un paquet envoyé = un paquet reçu
 Avec paquets tronqués si taille émission ou réception pas  Réalise une pseudo connexion
adaptée  La socket locale est configurée alors pour n'envoyer des paquets
qu'à l'adresse de la socket passée en paramètre du connect
 En TCP : mode connecté, communication par flux  Peut alors utiliser les services send/write et read/recv à la
 Un bloc de données envoyé n'est pas forcément reçu en place de sendto et recvfrom
un seul bloc d'un coup  Attention
 La couche TCP peut  Pas d'établissement de vraie connexion : juste une mémorisation
 Découper un bloc émis et le délivrer en plusieurs blocs de l'adresse destinataire pour simplifier émission
 Si destinataire pas prêt à recevoir les données, elles seront perdues
 Plusieurs read renverront les données d'un seul write
 N'offre donc pas non plus une communication fiable à la TCP
 Concaténer plusieurs blocs émis en un seul bloc reçu
 Une fois connectée, une socket UDP ne peut plus émettre des
 Un read renverra les données de plusieurs write paquets vers une autre adresse que celle de la pseudo
 Toujours vérifier la taille des données reçues, connexion
79 80
notamment lorsque l'on envoie des structures de données

Pseudo-connexion en UDP Informations sur la socket distante


 Exemple de pseudo-connexion
 En TCP ou pseudo-connexion pour UDP
 La socket locale n'est utilisée que pour envoyer des
données au port 4000 de la machine scinfe122  Possibilité de connaître les identifiants de la socket
distante avec qui la socket locale est connectée
 ...
sock = socket(AF_INET, SOCK_DGRAM, 0);  int getpeername(int sock,
host = gethostbyname("scinfe122"); (struct sockaddr *) adresse,
bzero((char *) &adresse, sizeof(adresse)); socklen_t *lg_adresse);
adresse.sin_family = AF_INET;
adresse.sin_port = htons(4000);  Paramètres
memcpy(&adresse.sin_addr.s_addr, host -> h_addr,
host -> h_length);
 sock : descripteur de la socket locale
// on fait la connexion  adresse : contiendra l'adresse de la socket distante
connect(sock, (struct sockaddr*)&adresse, lg);  lg_adresse : contiendra la taille de l'adresse
// on peut utiliser alors la fonction write pour émission
write(sock, msg, lg_msg);  A initialiser avant d'appeler la fonction
...
81 82

Sockets TCP en Java


 Respecte le fonctionnement de base des sockets
TCP, comme en C
 Mode connecté
 Connexion explicite du client au serveur
Sockets TCP en Java  Communication fiable, pas de perte de données
 Particularité par rapport au sockets TCP/UDP en C
et sockets UDP en Java
 Les données échangées ne sont plus des tableaux
d'octets
 On utilise les flux Java
 Chaque socket possède un flux d'entrée et un flux de sortie
 Communication de haut niveau permettant d'envoyer facilement
83 n'importe quel objet ou donnée via des sockets TCP 84
Sockets TCP en Java Socket en mode connecté
 Classes du package [Link] utilisées pour
 Classe Socket
communication via TCP  Socket mode connecté
 InetAddress : codage des adresses IP  Constructeurs
 public Socket(InetAddress address, int port)
 Même classe que celle décrite dans la partie UDP et usage throws IOException
identique
 Crée une socket locale et la connecte à un port distant d'une
 Socket : socket mode connecté machine distante identifié par le couple address/port
 ServerSocket : socket d'attente de connexion du coté  Pas de service dédié de connexion, on se connecte à la partie serveur lors
de l’instanciation de la socket
server  public Socket(String address, int port)
throws IOException,UnknownHostException
 Idem mais avec nom de la machine au lieu de son adresse IP codée
 Lève l'exception UnknownHostException si le service de nom ne
parvient pas à identifier la machine
 Variante de ces 2 constructeurs pour préciser en plus un port
85 local sur lequel sera liée la socket créée 86

Socket en mode connecté Socket en mode connecté


 Classe Socket  Classe Socket
 Méthodes d'émission/réception de données  Méthodes « get »
 Contrairement aux sockets UDP, les sockets TCP n'offrent pas  int getPort()
directement de services pour émettre/recevoir des données  Renvoie le port distant avec lequel est connecté la socket
 On récupère les flux d'entrée/sorties associés à la socket  InetAddress getAddress()
 OutputStream getOutputStream()  Renvoie l'adresse IP de la machine distante
 Retourne le flux de sortie permettant d'envoyer des données via la  int getLocalPort()
socket  Renvoie le port local sur lequel est liée la socket
 InputStream getInputStream()
 Retourne le flux d'entrée permettant de recevoir des données via la
 public void setSoTimeout(int timeout)
socket throws SocketException
 Fermeture d'une socket  Positionne l'attente maximale en réception de données sur le
 public close() flux d'entrée de la socket
 Si temps dépassé lors d'une lecture : exception
 Ferme la socket et rompt la connexion avec la machine distante SocketTimeoutException est levée
87  Par défaut : temps infini en lecture sur le flux 88

Socket serveur Sockets TCP Java – exemple coté client


 Classe ServerSocket
 Socket d'attente de connexion, coté serveur uniquement  Même exemple qu'avec UDP
 Constructeurs  Connexion d'un client à un serveur
 public ServerSocket(int port) throws IOException  Envoi d'une chaîne par le client et réponse sous forme
 Crée une socket d'écoute (d'attente de connexion de la part de clients) d'une chaîne par le serveur
 La socket est liée au port dont le numéro est passé en paramètre
 L'exception est levée notamment si ce port est déjà lié à une socket
 Coté client
 Méthodes
 Socket accept() throws IOException // adresse IP du serveur
InetAddress adr = [Link]("scinfr222");
 Attente de connexion d'un client distant
 Quand connexion est faite, retourne une socket permettant de communiquer // ouverture de connexion avec le serveur sur le port 7777
avec le client : socket de service Socket socket = new Socket(adr, 7777);
 void setSoTimeout(int timeout) throws SocketException
 Positionne le temps maximum d'attente de connexion sur un accept
 Si temps écoulé, l'accept lève l'exception SocketTimeoutException
 Par défaut, attente infinie sur l'accept 89 90
Sockets TCP Java – exemple coté client Sockets TCP Java – exemple coté serveur
 Coté client (suite)  // serveur positionne sa socket d'écoute sur le port local 7777
ServerSocket serverSocket = new ServerSocket(7777);

// construction de flux objets à partir des flux de la socket // se met en attente de connexion de la part d'un client distant
ObjectOutputStream output = Socket socket = [Link]();
new ObjectOutputStream([Link]());
ObjectInputStream input = // connexion acceptée : récupère les flux objets pour communiquer
new ObjectInputStream([Link]()); // avec le client qui vient de se connecter
ObjectOutputStream output =
// écriture d'une chaîne dans le flux de sortie : c'est-à-dire envoi de new ObjectOutputStream([Link]());
// données au serveur ObjectInputStream input =
[Link](new String("youpi")); new ObjectInputStream([Link]());

// attente de réception de données venant du serveur (avec le readObject) // attente les données venant du client
// on sait qu'on attend une chaîne, on peut donc faire un cast directement String chaine = (String)[Link]();
String chaine = (String)[Link]();
[Link](" recu : "+chaine);
[Link](" recu du serveur : "+chaine);

91 92

Sockets TCP Java – exemple coté serveur Sockets TCP


 Coté serveur (suite)  Critique sockets TCP
// affiche les coordonnées du client qui vient de se connecter
[Link](" ca vient de : "
+[Link]()+":"+[Link]());
 Avantages
 Niveau d'abstraction plus élevé qu'avec UDP
// envoi d'une réponse au client  Mode connecté avec phase de connexion explicite
[Link](new String("bien recu"));  Flux d'entrée/sortie avec la mise en œuvre Java
 Fiable
 Quand manipule des flux d'objets
 Inconvénients
 Souvent utile de vérifier le type de l'objet reçu pour faire
un cast ensuite
 Plus difficile de gérer plusieurs clients en même temps
 Nécessite du parallélisme avec des threads/processus
 Utilise instanceof  Mais oblige une bonne structuration coté serveur
 Exemple
 String chaine; Personne pers;
Object obj = [Link]();
if (obj instanceof String) chaine = (String)obj;
if (obj instanceof Personne) pers = (Personne)obj;93 94

Sockets UDP ou TCP ? Sockets UDP ou TCP ?


 Choix entre UDP et TCP  Exemple de protocole utilisant UDP : NFS
 A priori simple  Network File System (NFS)
 TCP est fiable et mieux structuré  Accès à un système de fichiers distant
 Mais intérêt tout de même pour UDP dans certains cas  A priori TCP mieux adapté car besoin de fiabilité lors des
 Si la fiabilité n'est pas essentielle transferts des fichiers, mais
 Si la connexion entre les 2 applications n'est pas utile voire est  NFS est généralement utilisé au sein d'un réseau local
même contraignante  Peu de pertes de paquets
 Exemple  UDP est plus basique et donc plus rapide
 Un thermomètre envoie toutes les 5 secondes la température de  TCP gère un protocole assurant dans n'importe quel contexte la fiabilité, ce
qui implique de nombreux échanges supplémentaires entre les applications
l'air ambiant à un afficheur distant
(envoi de messages de contrôle, d'acquittement...)
 Pas grave de perdre une mesure de temps en temps  Peu de perte de paquet en UDP en local : peut directement gérer la fiabilité
 Le mode connexion oblige pour le thermomètre à tenter régulièrement de au niveau NFS ou applicatif et c'est moins coûteux en temps
rouvrir une connexion si l'afficheur est planté : code plus complexe
 Alors qu'en UDP, il suffit de relancer l'afficheur avec le thermomètre qui
 Dans ce contexte, il n'est pas pénalisant d'utiliser UDP au lieu de
envoie ses données quoiqu'il arrive, que l'afficheur soit fonctionnel 95 TCP pour NFS
96
ou pas  NFS fonctionne sur ces 2 couches
Application multi-clients
 Application client/serveur classique
 Un serveur
 Plusieurs clients
 Le serveur doit pouvoir répondre aux requêtes des
Gestion multi-clients clients sans contrainte sur l'ordre d'arrivée des requêtes
 Contraintes à prendre à compte
 Chaque élément (client ou serveur) s'exécute
indépendamment des autres et en parallèle des autres

97 98

Concurrence Gestion plusieurs clients


 Par principe, les éléments distants communicants  Particularité coté serveur en TCP
sont actifs en parallèle
 Une socket d'écoute sert à attendre les connexions des
 Plusieurs processus concurrents clients
 Avec processus en pause lors d'attente de messages  A la connexion d'un client, une socket de service est
 Exemple de flux d'exécution pour notre exemple de initialisée pour communiquer avec ce client
client/serveur précédent  Communication avec plusieurs clients pour le serveur
 Envoi de données à un client
temps  UDP : on précise l'adresse du client dans le paquet à envoyer
 TCP : on utilise la socket correspondant au client
 Réception de données venant d'un client quelconque
 UDP : se met en attente d'un paquet et regarde de qui il vient
 TCP : doit se mettre en attente de données sur toutes les
sockets actives
99 100

Sockets TCP – gestion plusieurs clients Sockets TCP – gestion plusieurs clients
 Fonctionnement de TCP impose des contraintes  Boucle de fonctionnement général d'un serveur
 Lecture sur une socket : opération bloquante pour gérer plusieurs clients
 Tant que des données ne sont pas reçues  while(true) {
 Attente de connexion : opération bloquante socketClient = acceptConnection();
 Jusqu'à la prochaine connexion d'un client distant newProcessus(socketClient); }
 Avec un seul flot d'exécution (processus/thread)
 Exemple
 Si ne sait pas quel est l'ordonnancement des arrivées des avec 2
données des clients ou de leur connexion au serveur clients →
 Impossible à gérer
 Donc nécessité de plusieurs processus ou threads
 Un processus en attente de connexion sur le port d'écoute
 Nouvelle connexion : un nouveau processus est créé pour
gérer la communication avec le nouveau client 101 102
C – gestion plusieurs clients TCP C – gestion des sockets
 Création d'un nouveau processus via un fork() à chaque  Le fork() duplique toutes les données du père au fils créé
connexion de client  Y compris sa table des descripteurs de fichier
 Le processus principal fait les accept() en boucle et crée un  Une socket est un descripteur de fichier
nouveau processus fils pour la communication avec un nouveau
client connecté  Le fils ferme la socket d'écoute
 while(1) {  Par principe, il n'en a pas besoin, ce n'est pas son rôle de gérer
socket_service = accept(socket_ecoute, les demandes de connexion
(struct sockaddr *)&addr_client,&lg_addr);
if (fork() == 0) {  Ne ferme pas physiquement la socket d'écoute car le père a
// on est dans le fils toujours son descripteur ouvert
close(socket_ecoute);  Le père ferme la socket de service qui vient d'être créée
// fonction qui gère la communication avec le client
traiter_communication(socket_service);  Là aussi, par principe, le père n'en a pas besoin
exit(0);  Mais c'est surtout indispensable parce qu'au fil du temps sa table
} des descripteurs de fichier se remplit avec les connexions et une
close(socket_service); fois pleine, plus aucune connexion ne peut être acceptée
} 103 104

C – gestion processus Java – gestion plusieurs clients TCP


 Serveur multi-processus précédent
 Les processus fils deviennent des zombis une fois terminés  Coté serveur
 Pour supprimer ce problème, exécuter avant la boucle  Crée un thread Java dédié à la communication avec le
 signal(SIGCHLD, SIG_IGN); client qui vient de se connecter
 Peut aussi associer une fonction handler à SIGCHLD
 Cf TD/TP
 Mais en général on ne fait rien à la terminaison du fils
 Pour que le serveur devienne un démon
 Au départ du lancement du serveur, on crée un fils qui exécute
un setsid() et on termine le processus principal
 Le code du serveur (la boucle principale) est exécutée via ce fils
...
if ( fork() != 0 ) exit(0);
setsid();
...
while(1) {
socket_service = accept(...)
... 105 106
}

Multicast
 On a vu comment faire communiquer des
applications 1 à 1 via des sockets UDP ou TCP
 UDP offre un autre mode de communication : multicast
 Plusieurs récepteurs pour une seule émission d'un paquet
Multicast UDP/IP  Broadcast, multicast
 Broadcast (diffusion) : envoi de données à tous les éléments
d'un réseau
 Multicast : envoi de données à un sous-groupe de tous les
éléments d'un réseau
 Multicast IP
 Envoi d'un datagramme sur une adresse IP particulière
 Plusieurs éléments lisent à cette adresse IP
107 108
Multicast Multicast
 Adresse IP multicast  Utilités du multicast UDP/IP
 Classe d'adresse IP entre [Link] et [Link]
 Évite d'avoir à créer X connexions et/ou d'envoyer X fois
 Classe D la même donnée à X machines différentes
 Adresses entre [Link] et [Link] sont utilisables par
un programme quelconque  En pratique
 Les autres sont réservées  Utilisé pour diffuser des informations
 Une adresse IP multicast n'identifie pas une machine sur  Diffusion de flux vidéos à plusieurs récepteurs
un réseau mais un groupe multicast  Chaîne de télévision, diffusion d'une conférence
 Le même flux est envoyé à tous au même moment
 Socket UDP multicast  Pour récupérer des informations sur le réseau
 Avant envoi de paquet : on doit rejoindre un groupe  [Link] : pour localiser un serveur DHCP
 Identifié par un couple : @IP multicast/numéro port  Limites
 Un paquet envoyé par un membre du groupe est reçu  Non fiable et non connecté comme UDP
par tous les membres de ce groupe
109 110

Configuration des sockets


 Pour utiliser le multicast en C
Sockets en C  Doit passer par la configuration des sockets
 Configuration socket/couche IP
Configuration des options des sockets  Accès aux options d'une socket
&  Lire l'état d'une option : getsockopt
int getsockopt(int sock, int niveau, int option,
Broadcast, multicast UDP/IP

void *valeur, socklen_t *longueur)
 Modifier l'état d'une option : setsockopt
 int setsockopt(int sock, int niveau, int option,
void *valeur, socklen_t longeur)
 Ces fonctions retournent -1 si problème

111 112

Configuration des sockets Configuration des sockets


 Paramètres de [get/set]sockopt  Paramètres de [get/set]sockopt (suite)
 sock : la socket que l'on veut gérer  valeur : données décrivant l'état de l'option
 niveau : le niveau du protocole choisi, valeurs entre autres parmi  En général, on utilise un entier ayant pour valeur 0 ou 1
 SOL_SOCKET : la socket elle même  0 : l'option n'est pas positionnée
 IPPROTO_IP : la couche IP  1 : l'option est positionnée
 IPPROTO_TCP : la couche TCP  longueur : longueur du champ valeur
 IPPROTO_UDP : la couche UDP  Exemple pour faire de la diffusion (broadcast)
 option : option choisie
 int autorisation, sock;
 Notamment pour le niveau SOL_SOCKET sock = socket(AF_INET, SOCK_DGRAM, 0);
 SO_BROADCAST : autorisation de diffusion des paquets autorisation = 1;
 SO_RVCBUF/SO_SNDBUF : taille des buffers de réception et d'émission setsockopt(SOL_SOCKET, SO_BROADCAST, &autorisation,
 SO_REUSEADDR : autorise de lier plusieurs sockets au même port sizeof(int));
 SO_TYPE (avec get) : retourne le type de la socket (SOCK_DGRAM ...)  On diffuse les paquets en utilisant l'adresse de diffusion du réseau
 Notamment pour le niveau IP_PROTO  Adresse IP dont tous les bits codant la machine sont à 1
 IP_[ADD/DROP]_MEMBERSHIP : inscription ou désinscription d'un groupe
 Ex pour machine [Link] de classe C : adresse de diffusion =
multicast [Link]
 IP_MULTICAST_LOOP : paquet diffusé est reçu ou pas à son émetteur
 Toutes les machines connectés au réseau recevront ce paquet
 IP_MULTICAST_TTL : TTL d'un paquet envoyé en multicast 113 114
 Attention à lire sur le même port que celui utilisé pour l'émission
Réalisation de multicast en C Réalisation de multicast en C
 Pour initialiser une socket UDP en mode multicast,
 Pour décrire le groupe multicast, structure ip_mreq actions à effectuer
 struct ip_mreq { 1. Créer la socket UDP de manière normale
struct in_addr imr_multiaddr;
struct in_addr imr_interface; 2. Créer l'objet ip_mreq
}; 3. Associer cet objet ip_mreq à la socket avec l'option
 imr_multiaddr : adresse IP multicast IP_ADD_MEMBERSHIP
 imr_interface : adresse IP locale ou interface locale  Abonnement au groupe multicast
 On utilisera par défaut INADDR_ANY 4. Éventuellement appliquer l'option SO_REUSEADDR
 Sinon on ne peut pas avoir 2 programmes utilisant le même
groupe multicast sur la même machine à cause du bind réalisé
5. Lier la socket au numéro de port du groupe
 Émission d'un paquet
115  On utilise le couple @IP du groupe/port du groupe 116

Multicast : exemple Multicast : exemple


 Adresse/port du groupe : [Link]:1234  // abonnement de la socket au groupe multicast
setsockopt(sock, IPPROTO_IP, IP_ADD_MEMBERSHIP,
 Note : les erreurs ne sont pas gérées &gr_multicast, sizeof(struct ip_mreq));
 int sock;
struct in_addr ip; // autorise de lier plusieurs sockets sur le port utilisé par cette
static struct sockaddr_in ad_multicast, adresse; // socket, c'est-à-dire sur le port du groupe multicast
ip_mreq gr_multicast; int reuse = 1;
setsockopt(sock, SOL_SOCKET, SO_REUSEADDR,
// création de la socket UDP (int *)&reuse, sizeof(reuse));
sock = socket(AF_INET, SOCK_DGRAM, 0);
// liaison de la socket au port du groupe multicast
// récupération adresse ip du groupe bzero((char *) &adresse, sizeof(adresse));
inet_aton("[Link]", &ip); ad_multicast.sin_family = AF_INET;
ad_multicast.sin_addr.s_addr = htons(INADDR_ANY);
// création identificateur du groupe ad_multicast.sin_port = htons(1234);
gr_multicast.imr_multiaddr.s_addr = ip.s_addr; bind(sock, &adresse, sizeof(struct sockaddr_in));
gr_multicast.imr_interface.s_addr =
htons(INADDR_ANY);
117 118

Multicast : exemple
 // émission d'un paquet :
// on l'envoie au couple @/port du groupe
static struct sockaddr_in adresse;
int longueur_adresse = sizeof(struct sockaddr_in);
bzero((char *) &adresse, sizeof(adresse));
adresse.sin_family = AF_INET;
adresse.sin_addr.s_addr = ip.s_addr; Multicast en Java
adresse.sin_port = htons(1234);
sendto(sock, message, tailleMessage , 0,
(struct sockaddr*)&adresse, longueur_adresse);

// réception d'un paquet : avec recvfrom ou peut utiliser


// aussi recv car ne recevra des paquets que venant du groupe
recv(sock, buffer, TAILLEBUFFER, 0);

119 120
Multicast UDP en Java Multicast UDP en Java
 Classe [Link]  Classe [Link] (suite)
 Spécialisation de DatagramSocket  Gestion des groupes
 Constructeurs : identiques à ceux de DatagramSocket  public void joinGroup(InetAddress mcastaddr)
throws IOException
 public MulticastSocket() throws SocketException  Rejoint le groupe dont l'adresse IP multicast est passée en
 Crée une nouvelle socket en la liant à un port quelconque libre paramètre
 Exception levée en cas de problème (a priori il doit pas y en avoir)  L'exception est levée en cas de problèmes, notamment si l'adresse
 public MulticastSocket(int port) IP n'est pas une adresse IP multicast valide
throws SocketException  public void leaveGroup(InetAddress mcastaddr)
 Crée une nouvelle socket en la liant au port précisé par le throws IOException
paramètre port : c'est le port qui identifie le groupe de multicast  Quitte un groupe de multicast
 Exception levée en cas de problème  L'exception est levée si l'adresse IP n'est pas une adresse IP
multicast valide
 Pas d'exception levée ou de problème quand on quitte un groupe
auquel on appartient pas
121 122

Multicast UDP en Java Multicast UDP en Java


 Classe [Link] (suite)  Exemple de communication via socket multicast UDP
 Emission/réception de données // adresse IP multicast du groupe
InetAddress group = [Link]("[Link]");
 On utilise les services send() et receive() avec des
paquets de type DatagramPacket tout comme avec une // socket UDP multicast pour communiquer avec groupe [Link]:4000
socket UDP standard MulticastSocket socket = new MulticastSocket(4000);

 Exemple, exécution dans l'ordre : // données à envoyer


byte[] data = (new String("youpi")).getBytes();
 Connexion à un groupe
// paquet à envoyer (en précisant le couple @IP/port du groupe)
 Envoi d'un paquet DatagramPacket packet =
 Réception d'un paquet new DatagramPacket(data, [Link], group, 4000);

 Quitte le groupe // on joint le groupe


[Link](group);

123 124

Multicast UDP en Java


 Exemple (suite)
// on envoie le paquet
[Link](packet);

// attend un paquet en réponse


[Link](packet);

// traite le résultat
...
// quitte le groupe
[Link](group);
 Notes
 Il est possible que le receive récupère le paquet que le send vient
juste d'envoyer
 Besoin d'un autre receive pour réponse venant d'un autre élément
125

Vous aimerez peut-être aussi