0% ont trouvé ce document utile (0 vote)
168 vues118 pages

Sockets UDP en Java : Guide Complet

Ce document décrit les sockets UDP et leur mise en œuvre en Java. Il présente les classes clés comme DatagramSocket, DatagramPacket et InetAddress pour la communication non connectée via UDP.

Transféré par

nathan tatchou
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)
168 vues118 pages

Sockets UDP en Java : Guide Complet

Ce document décrit les sockets UDP et leur mise en œuvre en Java. Il présente les classes clés comme DatagramSocket, DatagramPacket et InetAddress pour la communication non connectée via UDP.

Transféré par

nathan tatchou
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

Sockets TCP/UDP et leur


mise en œuvre en Java

Eric Cariou

Université de Pau et des Pays de l'Adour


Département Informatique

[Link]@[Link]
1
Plan
1. Sockets UDP
2. Les flux Java
3. Sockets TCP
4. Multicast IP
5. Concurrence
1. Les threads Java
2. Synchronisation en Java

2
Rappel sur les réseaux
 TCP ou UDP
 Communication entre systèmes aux extrémités
 Pas de visibilité des systèmes intermédiaires

Application Application
Communication d’extrémité
à extrémité
TCP/UDP TCP/UDP
IP IP IP
Liaison Liaison Liaison
Physique Physique Physique
3
Adressage
 Adressage pour communication entre applications
 Adresse « réseau » application = couple de 2 informations
 Adresse IP et numéro de port
 Couche réseau : adresse IP
 Ex : [Link]
 Couche transport : numéro de port TCP ou UDP
 Ce numéro est en entier d'une valeur quelconque
 Ports < 1024 : réservés pour les applications ou protocoles systèmes
 Exemple : 80 = HTTP, 21 = FTP, ...
 Sur un port : réception ou envoi de données
 Adresse notée : @IP:port ou nomMachine:port
 [Link]:80 : accès au serveur Web tournant sur la machine
d'adresse IP [Link]
4
Sockets
 Socket : prise
 Associée, liée à un port
 C'est donc 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
communication à distance
 Une socket peut-être liée
 Sur un port précis à la demande du programme
 Sur un port quelconque libre déterminé par le système
5
Sockets

 Une socket est


 Un point d'accès aux couches réseau TCP/UDP
 Liée localement à un port
 Adressage de l'application sur le réseau : son couple @IP:port
 Elle permet la communication avec un port distant sur une
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
 Différenciation pour plusieurs raisons
 Identification : on doit connaître précisément la localisation
d'un des 2 éléments communiquants
 Le coté serveur communique via une socket liée à un port
précis : port d'écoute
 Dissymétrie de la communication/connexion
 Le client initie la connexion ou la communication
7
Sockets UDP

8
Sockets UDP : principe
 Mode datagramme
 Envois de paquets de données (datagrammes)
 Pas de connexion entre parties client et serveur
 Pas de fiabilité ou de gestion de la communication
 Un paquet peut ne pas arrivé (perdu par le réseau)
 Un paquet P2 envoyé après un paquet P1 peut arriver avant
ce paquet P1 (selon la gestion des routes dans le réseau)
 Principe de communication
 La partie serveur crée une socket et la lie à un port
UDP particulier
 La partie client crée une socket pour accéder à la
couche UDP et la lie sur un port quelconque
9
Sockets UDP : principe
 Principe de communication (suite)
 Le serveur se met en attente de réception de paquet sur
sa socket
 Le client envoie un paquet via sa socket en précisant
l'adresse du destinataire
 Couple @IP/port
 Destinataire = partie serveur
 @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
 Il est reçu par le serveur (sauf pb réseau)
 Si le client envoie un paquet avant que le serveur ne soit
prêt à recevoir : le paquet est perdu

10
Sockets UDP en Java
 Java intègre nativement les fonctionnalités de
communication réseau au dessus de TCP-UDP/IP
 Package [Link]
 Classes utilisées pour communication via UDP
 InetAddress : codage des adresses IP
 DatagramSocket : socket mode non connecté (UDP)
 DatagramPacket : paquet de données envoyé via une
socket sans connexion (UDP)

11
Sockets UDP en Java
 Classe InetAddress
 Constructeurs
 Pas de constructeurs, on passe par des méthodes statiques
pour créer un objet
 Méthodes
 public static InetAddress getByName(String host)
throws UnknownHostException
 Crée un objet InetAddress identifiant une machine dont le nom est
passé en paramètre
 L'exception est levée si le service de nom (DNS...) du système ne
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
12
Sockets UDP en Java
 Classe InetAddress
 Méthodes (suite)
 public static InetAddress getLocalHost()
throws UnknownHostException
 Retourne l'adresse IP de la machine sur laquelle tourne le
programme, c'est-à-dire l'adresse IP locale
 public String getHostName()
 Retourne le nom de la machine dont l'adresse est codée par l'objet
InetAddress

13
Sockets UDP en Java
 Classe DatagramPacket
 Structure des données en mode datagramme
 Constructeurs
 public DatagramPacket(byte[] buf, int length)
 Création d'un paquet pour recevoir des données (sous forme d'un
tableau d'octets)
 Les données reçues seront placées dans buf
 length précise la taille max de données à lire
 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

14
Sockets UDP en Java
 Classe DatagramPacket
 Constructeurs (suite)
 public DatagramPacket(byte[] buf, int length,
InetAddress address, int port)
 Création d'un paquet pour envoyer des données (sous forme d'un
tableau d'octets)
 buf : contient les données à envoyer
 length : longueur des données à envoyer
 Ne pas préciser une taille supérieure à celle de buf
 address : adresse IP de la machine destinataire des données
 port : numéro de port distant (sur la machine destinataire) où
envoyer les données

15
Sockets UDP en Java
 Classe DatagramPacket
 Méthodes « get »
 InetAddress getAddress()
 Si paquet à envoyer : adresse de la machine destinataire
 Si paquet reçu : adresse de la machine qui a envoyé le paquet
 int getPort()
 Si paquet à envoyer : port destinataire sur la machine distante
 Si paquet reçu : port utilisé par le programme distant pour envoyer le
paquet
 byte[] getData
 Données contenues dans le paquet
 int getLength()
 Si paquet à envoyer : longueur des données à envoyer
 Si paquet reçu : longueur des données reçues
16
Sockets UDP en Java
 Classe DatagramPacket
 Méthodes « set »
 void setAddress(InetAdress adr)
 Positionne l'adresse IP de la machine destinataire du paquet
 void setPort(int port)
 Positionne le port destinataire du paquet pour la machine distante
 void setData(byte[] data)
 Positionne les données à envoyer
 int setLength(int length)
 Positionne la longueur des données à envoyer

17
Sockets UDP en Java
 Classe DatagramPacket, complément sur les
tailles des données envoyées
 Java n'impose aucune limite en taille pour les tableaux
d'octets circulant dans les paquets UDP, mais
 Pour tenir dans un seul datagramme IP, le datagramme UDP ne
doit pas contenir plus de 65467 octets de données
 Un datagramme UDP est rarement envoyé via plusieurs datagrammes IP
 Mais en pratique : il est conseillé de ne pas dépasser 8176 octets
 Car la plupart des systèmes limitent à 8 Ko la taille des datagrammes UDP
 Pour être certain de ne pas perdre de données : 512 octets max
 Si datagramme UDP trop grand : les données sont tronquées
 Si tableau d'octets en réception est plus petit que les
données envoyées
 Les données reçues sont généralement tronquées
18
Sockets UDP en Java
 Classe DatagramSocket
 Socket en mode datagramme
 Constructeurs
 public DatagramSocket() throws SocketException
 Crée une nouvelle socket en la liant à un port quelconque libre
 Exception levée en cas de problème (a priori il doit pas y en avoir)
 public DatagramSocket(int port)
throws SocketException
 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é

19
Sockets UDP en Java
 Classe DatagramSocket
 Méthodes d'émission/réception de paquet
 public void send(DatagramPacket p)
throws IOException
 Envoie le paquet passé en paramètre. Le destinataire est identifié par le
couple @IP/port précisé dans le paquet
 Exception levée en cas de problème d'entrée/sortie
 public void receive(DatagramPacket p)
throws IOException
 Reçoit un paquet de données
 Bloquant tant qu'un paquet n'est pas reçu
 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
lors de la création de p et sa longueur est positionnée avec la taille des
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 20
Sockets UDP en Java
 Classe DatagramSocket
 Autres méthodes
 public void close()
 Ferme la socket et libère le port à laquelle elle était liée
 public int getLocalPort()
 Retourne le port local sur lequel est liée la socket
 Possibilité de créer un canal (mais toujours en mode
non connecté)
 Pour restreindre la communication avec un seul destinataire
distant
 Car par défaut peut recevoir sur la socket des paquets venant
de n'importe où

21
Sockets UDP en Java
 Classe DatagramSocket
 Réception de données : via méthode receive
 Méthode bloquante sans contrainte de temps : peut rester en
attente indéfiniment si aucun paquet n'est jamais reçu
 Possibilité de préciser un délai maximum d'attente
 public void setSoTimeout(int timeout)
throws SocketException
 L'appel de la méthode receive sera bloquante pendant au plus
timeout millisecondes
 Une méthode receive se terminera alors de 2 façons
 Elle retourne normalement si un paquet est reçu en moins du temps
positionné par l'appel de setSoTimeout
 L'exception SocketTimeoutException est levée pour indiquer que le
délai s'est écoulé avant qu'un paquet ne soit reçu
 SocketTimeoutException est une sous-classe de IOException
22
Sockets UDP Java – exemple coté client
 InetAddress adr;
DatagramPacket packet;
DatagramSocket socket;

// adr contient l'@IP de la partie serveur


adr = [Link]("scinfr222");

// données à envoyer : chaîne de caractères


byte[] data = (new String("youpi")).getBytes();

// création du paquet avec les données et en précisant l'adresse du serveur


// (@IP et port sur lequel il écoute : 7777)
packet = new DatagramPacket(data, [Link], adr, 7777);

// création d'une socket, sans la lier à un port particulier


socket = new DatagramSocket();

// envoi du paquet via la socket


[Link](packet);

23
Sockets UDP Java – exemple coté serveur
 DatagramSocket socket;
DatagramPacket packet;

// création d'une socket liée au port 7777


DatagramSocket socket = new DatagramSocket(7777);

// tableau de 15 octets qui contiendra les données reçues


byte[] data = new byte[15];

// création d'un paquet en utilisant le tableau d'octets


packet = new DatagramPacket(data, [Link]);

// attente de la réception d'un paquet. Le paquet reçu est placé dans


// packet et ses données dans data.
[Link](packet);

// récupération et affichage des données (une chaîne de caractères)


String chaine = new String([Link](), 0,
[Link]());
[Link](" recu : "+chaine);
24
Sockets UDP en Java – exemple suite
 La communication se fait souvent dans les 2 sens
 Le serveur doit donc connaître la localisation du client
 Elle est précisée dans le paquet qu'il reçoit du client
 Réponse au client, coté serveur
 [Link](" ca vient de :
"+[Link]()+":"+ [Link]());

// on met une nouvelle donnée dans le paquet


// (qui contient donc le couple @IP/port de la socket coté client)
[Link]((new String("bien recu")).getBytes());

// on envoie le paquet au client


[Link](packet);

25
Sockets UDP en Java – exemple suite
 Réception réponse du serveur, coté client

// attente paquet envoyé sur la socket du client


[Link](packet);

// récupération et affichage de la donnée contenue dans le paquet


String chaine = new String([Link](), 0,
[Link]());
[Link](" recu du serveur : "+chaine);

26
Critique sockets UDP
 Avantages
 Simple à programmer (et à appréhender)
 Inconvénients
 Pas fiable
 Ne permet d'envoyer que des tableaux de byte

27
Structure des données échangées
 Format des données à transmettre
 Très limité a priori : tableaux de byte
 Et attention à la taille réservée : si le récepteur réserve un
tableau trop petit par rapport à celui envoyé, une partie des
données est perdue
 Doit donc pouvoir convertir
 Un objet quelconque en byte[] pour l'envoyer
 Un byte[] en un objet d'un certain type après réception
 Deux solutions
 Créer les méthodes qui font cela : lourd et dommage de faire
des tâches de si « bas-niveau » avec un langage évolué
comme Java
 Utiliser les flux Java pour conversion automatique (voir suite)
28
Flux Java

29
Flux Java
 En Java, toutes les entrées/sorties sont gérées via
des flux
 Entrées/sorties standards (clavier/console)
 Fichiers
 Sockets
 ...
 Flux : tuyaux dans lesquels on envoie ou lit des
séries de données
 Information de base qui transite dans un flux : l'octet

30
Flux Java standards
 Flux d'entrées/sortie standards
 [Link]
 Sortie standard, flux de type PrintStream
 [Link](''nombre = ''+nb);
 [Link]
 Sortie d'erreur strandard, flux de type PrintStream
 [Link]
 Entrée standard, flux de type InputStream
 while ((c = (char)[Link]()) != 'z')
[Link](c);

31
Hiérarchie de flux Java
 Java définit une hiérarchie de flux composée de plusieurs
dizaines de classes (de types de flux différents)
 Package [Link]
 Deux classifications transverses
 Flux est soit d'entrée, soit de sortie
 Entrée : le programme lit des informations à partir du flux
 Sortie : le programme écrit des informations dans le flux
 Nature de l'information transitant sur le flux
 Binaire : octet par octet
 Caractère : 2 octets par 2 octets
 Codage unicode sur 16 bits

32
Hiérarchie de flux Java
 Hiérarchie principale
 Flux de base
 Flux avec tampon
 Flux d'accès aux fichiers
 Flux de filtrage
 Flux d'impression
 Flux enchaînés par des « pipes »
 Flux de concaténation de plusieurs flux en un seul
 Flux de conversion flux caractère/flux binaire
 Flux de lecture/écriture de différents types
 int, char ... ou bien encore un objet quelconque (Object)
 Données codées indépendamment de la plateforme/système
33
Hiérarchie de flux Java
 Flux binaire, entrée

34
Hiérarchie de flux Java
 Flux binaire, sortie

35
Hiérarchie de flux Java
 Flux caractère, entrée

36
Hiérarchie de flux Java
 Flux caractère, sortie

37
Hiérarchie de flux Java
 Autres types de flux
 Package [Link]
 Compression données : GZIPInputStream, ZipInputStream ...
 Vérification intégrité données (CRC) : CheckedInputStream ...
 Package [Link]
 Cryptage des données : CipherInputStream ...
 Et d'autres ...
 Les flux peuvent être dépendants les uns des autres
 Un flux est créé à partir d'un autre (par « wrapping ») : il traite
les mêmes données mais avec un traitement supplémentaire
 Codage des données dans un autre type
 Filtrage des données, mise en tapon ...
 Un flux est chaîné à un autre par un pipe
38
Méthodes des classes Stream
 Méthodes générales d'accès aux données du flux
 Flux en entrée (InputStream)
 int read()
 Lecture d'un octet (sous forme de int) dans le flux
 int read(byte[] tab)
 Lit une suite d'octets en les plaçant dans tab
 Lit au plus la longueur de tab
 Retourne le nombre d'octets lu
 Autres méthodes pour se placer à un endroit donné du flux ...
 int available()
 Retourne le nombre d'octets disponibles en lecture dans le flux
 void close()
 Ferme le flux
39
Méthodes des classes Stream
 Méthodes générales d'accès aux données du flux
 Flux en sortie (OutputStream)
 void write(int b)
 Écrit un octet (via un int) dans le flux
 void write(byte[])
 Écrit le contenu d'un tableau d'octets dans le flux
 void flush()
 Force l'écriture dans le flux de toutes les données à écrire
 Vide le tampon associé au flux en écrivant son contenu
 void close()
 Ferme le flux
 Flux en entrées ou sorties
 Méthodes générales : accès niveau octet
40
Méthodes des classes Stream
 Classes de flux spécialisées
 Offrent des méthodes d'accès plus évoluées que niveau octet
 Deux types de flux intéressants de ce point de vue
 Data[Input/Output]Stream
 Lecture/écriture de types primitifs Java
 int, char, boolean, double, long, byte, float, short
 Exemple pour double
 DataOutputStream : void writeDouble(double b)
 DataInputStream : double readDouble()
 Object[Input/Output]Stream
 Lecture/écriture d'objets de toute nature
 Très puissant et confortable
 ObjectOutputStream : void writeObject(Object o)
 ObjectInputStream : Object readObject()
41
Méthodes des classes Stream
 Data[Input/Output]Stream (suite)
 Exemple : écriture d'un objet de la classe Personne (classe
programmée n'appartenant pas à la hiérarchie Java)
 Personne pers = new Personne (''toto'', 24);
ObjectOutputStream output = .... ;
[Link](pers);
 Pour pouvoir envoyer un objet dans un flux
 Sa classe doit implémenter l'interface
[Link]
 Interface vide qui sert juste à préciser que les objets peuvent
être sérialisés
 C'est-à-dire peuvent être transformés en série de byte et sont donc
transmissibles via des flux

42
Méthodes des classes Stream
 Exceptions niveau flux
 La plupart des méthodes d'accès aux flux peuvent lever
l'exception [Link]
 Problème quelconque d'entrée/sortie ...
 Constructeurs
 Les flux évolués peuvent être construits à partir d'autres
flux existants
 Exemple : créer un ObjectOutputStream à partir d'un
FileOutputStream associé au fichier [Link]
 FileOutputStream fileOut=
new FileOutputStream(''[Link]'');
ObjectOutputStream objOut =
new ObjectOutputStream(fileOut);
// peut maintenant enregistrer tout objet dans [Link] via objOut
43
Exemple utilisation de flux Java
 Exemple concret d'utilisation de flux
 Écriture d'entiers dans un fichier
// ouverture d'un flux en sortie sur le fichier [Link]
FileOutputStream ficOut =
new FileOutputStream("[Link]");

// ouverture d'un flux de données en sortie à partir de ce flux


DataOutputStream dataOut =
new DataOutputStream(ficOut);

// écriture des entiers de 10 à 15 dans le fichier


for(int i=10;i<16;i++)
[Link](i);

// fermeture des flux


[Link]();
[Link]();
44
Exemple utilisation de flux Java
 Exemple concret d'utilisation de flux
 Lecture d'entiers à partir d'un fichier
// ouverture d'un flux en entrée sur le fichier [Link]
FileInputStream ficIn =
new FileInputStream("[Link]");

// ouverture d'un flux de données en entrée à partir de ce flux


DataInputStream dataIn = new DataInputStream(ficIn);

// tant que des données sont disponibles, on lit des entiers


while([Link]() > 0)
[Link]([Link]());

// fermeture des flux


[Link]();
[Link]();

45
Conversion Object <-> byte[]
 Pour émettre et recevoir n'importe quel objet via
des sockets UDP
 En écriture : conversion de Object en byte[]
ByteArrayOutputStream byteStream =
new ByteArrayOutputStream();
ObjectOutputStream objectStream =
new ObjectOutputStream(byteStream);
[Link](object);
byte[] byteArray = [Link]();
 En lecture : conversion de byte[] en Object
ByteArrayInputStream byteStream =
new ByteArrayInputStream(byteArray);
ObjectInputStream objectStream =
new ObjectInputStream(byteStream);
object = [Link]();
46
Sockets TCP

47
Sockets TCP : principe
 Fonctionnement en mode connecté
 Données envoyées dans un « tuyau » et non pas par paquet
 Flux de données
 Correspond aux flux Java dans la mise en oeuvre Java des sockets TCP
 Fiable : la couche TCP assure que
 Les données envoyées sont toutes reçues par la machine destinataire
 Les données sont reçues dans l'ordre où elles ont été envoyées

48
Sockets TCP : principe
 Principe de communication
 Le serveur lie une socket 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 appelle un service pour ouvrir une connexion
avec le serveur
 Il récupère une socket (associée à un port quelconque par le
système)
 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
 Comme avec sockets UDP : le client et le serveur
communiquent en envoyant et recevant des données via leur
socket
49
Sockets TCP en Java
 Classes du package [Link] utilisées pour
communication via TCP
 InetAddress : codage des adresses IP
 Même classe que celle décrite dans la partie UDP et usage
identique
 Socket : socket mode connecté
 ServerSocket : socket d'attente de connexion du coté
server

50
Sockets TCP en Java
 Classe Socket
 Socket mode connecté
 Constructeurs
 public Socket(InetAddress address, int port)
throws IOException
 Crée une socket locale et la connecte à un port distant d'une machine
distante identifié par le couple address/port
 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 local
sur lequel sera liée la socket créée
51
Sockets TCP en Java
 Classe Socket
 Méthodes d'émission/réception de données
 Contrairement aux sockets UDP, les sockets TCP n'offre pas
directement de services pour émettre/recevoir des données
 On récupère les flux d'entrée/sorties associés à la socket
 OutputStream getOutputStream()
 Retourne le flux de sortie permettant d'envoyer des données via la
socket
 InputStream getInputStream()
 Retourne le flux d'entrée permettant de recevoir des données via la
socket
 Fermeture d'une socket
 public close()
 Ferme la socket et rompt la connexion avec la machine distante

52
Sockets TCP en Java
 Classe Socket
 Méthodes « get »
 int getPort()
 Renvoie le port distant avec lequel est connecté la socket
 InetAddress getAddress()
 Renvoie l'adresse IP de la machine distante
 int getLocalPort()
 Renvoie le port local sur lequel est liée la socket
 public void setSoTimeout(int timeout)
throws SocketException
 Positionne l'attente maximale en réception de données sur le
flux d'entrée de la socket
 Si temps dépassé lors d'une lecture : exception
SocketTimeoutException est levée
 Par défaut : temps infini en lecture sur le flux
53
Sockets TCP en Java
 Classe ServerSocket
 Socket d'attente de connexion, coté serveur uniquement
 Constructeurs
 public ServerSocket(int port) throws IOException
 Crée une socket d'écoute (d'attente de connexion de la part de clients)
 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

 Méthodes
 Socket accept() throws IOException
 Attente de connexion d'un client distant
 Quand connexion est faite, retourne une socket permettant de
communiquer avec le client : socket de service
 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 54
Sockets TCP Java – exemple coté client
 Même exemple qu'avec UDP
 Connexion d'un client à un serveur
 Envoi d'une chaîne par le client et réponse sous forme
d'une chaîne par le serveur
 Coté client

// adresse IP du serveur
InetAddress adr = [Link]("scinfr222");

// ouverture de connexion avec le serveur sur le port 7777


Socket socket = new Socket(adr, 7777);

55
Sockets TCP Java – exemple coté client
 Coté client (suite)

// construction de flux objets à partir des flux de la socket


ObjectOutputStream output =
new ObjectOutputStream([Link]());
ObjectInputStream input =
new ObjectInputStream([Link]());

// écriture d'une chaîne dans le flux de sortie : c'est-à-dire envoi de


// données au serveur
[Link](new String("youpi"));

// attente de réception de données venant du serveur (avec le readObject)


// on sait qu'on attend une chaîne, on peut donc faire un cast directement
String chaine = (String)[Link]();
[Link](" recu du serveur : "+chaine);

56
Sockets TCP Java – exemple coté serveur
 // serveur positionne sa socket d'écoute sur le port local 7777
ServerSocket serverSocket = new ServerSocket(7777);

// se met en attente de connexion de la part d'un client distant


Socket socket = [Link]();

// connexion acceptée : récupère les flux objets pour communiquer


// avec le client qui vient de se connecter
ObjectOutputStream output =
new ObjectOutputStream([Link]());
ObjectInputStream input =
new ObjectInputStream([Link]());

// attente les données venant du client


String chaine = (String)[Link]();
[Link](" recu : "+chaine);

57
Sockets TCP Java – exemple coté serveur
 Coté serveur (suite)
// affiche les coordonnées du client qui vient de se connecter
[Link](" ca vient de : "
+[Link]()+":"+[Link]());

// envoi d'une réponse au client


[Link](new String("bien recu"));

 Quand manipule des flux d'objets


 Souvent utile de vérifier le type de l'objet reçu
 Utilise instanceof
 Exemple
 String chaine; Personne pers;
Object obj = [Link]();
if (obj instanceof String) chaine = (String)obj;
if (obj instanceof Personne) pers = (Personne)obj;
58
Sockets TCP
 Critique sockets TCP
 Avantages
 Niveau d'abstraction plus élevé qu'avec UDP
 Mode connecté avec phase de connexion explicite
 Flux d'entrée/sortie
 Fiable
 Inconvénients
 Plus difficile de gérer plusieurs clients en même temps
 Nécessite du parallélisme avec des threads (voir suite cours)
 Mais oblige une bonne structuration coté serveur

59
Sockets UDP ou TCP ?
 Choix entre UDP et TCP
 A priori simple
 TCP est fiable et mieux structuré
 Mais intérêt tout de même pour UDP dans certains cas
 Si la fiabilité n'est pas essentielle
 Si la connexion entre les 2 applications n'est pas utile
 Exemple
 Un thermomètre envoie toutes les 5 secondes la température de
l'air ambiant à un afficheur distant
 Pas grave de perdre une mesure de temps en temps
 Pas grave d'envoyer les mesures même si l'afficheur est absent

60
Sockets UDP ou TCP ?
 Exemple de protocole utilisant UDP : NFS
 Network File System (NFS)
 Accès à un système de fichiers distant
 A priori TCP mieux adapté car besoin de fiabilité lors des
transferts des fichiers, mais
 NFS est généralement utilisé au sein d'un réseau local
 Peu de pertes de paquets
 UDP est plus basique et donc plus rapide
 TCP gère un protocole assurant la fiabilité impliquant de nombreux
échanges supplémentaires entre les applications (envoi d'acquittement...)
 Peu de perte de paquet en UDP en local : peu directement gérer la fiabilité
au niveau NFS ou applicatif et c'est moins couteux en temps
 Dans ce contexte, il n'est pas pénalisant d'utiliser UDP au lieu de
TCP pour NFS
 NFS fonctionne sur ces 2 couches
61
Multicast IP

62
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
 Broadcast, multicast
 Broadcast (diffusion) : envoi de données à tous les éléments
d'un réseau
 Multicast : envoie 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
63
Multicast
 Adresse IP multicast
 Classe d'adresse IP entre [Link] et [Link]
 Classe D
 Adresses entre [Link] et [Link] sont utilisables par
un programme quelconque
 Les autres sont réservées
 Une adresse IP multicast n'identifie pas une machine sur
un réseau mais un groupe multicast
 Socket UDP multicast
 Avant envoi de paquet : on doit rejoindre un groupe
 Identifié par un couple : @IP multicast/numéro port
 Un paquet envoyé par un membre du groupe est reçu par
tous les membres de ce groupe
64
Multicast
 Utilités du multicast UDP/IP
 Evite d'avoir à créer X connexions et/ou d'envoyer X fois
la même donnée à X machines différentes
 En pratique
 Utilisé pour diffuser des informations
 Diffusion de flux vidéos à plusieurs récepteurs
 Chaine de télévision, diffusion d'une conférence
 Le même flux est envoyé à tous au même moment
 Pour récupérer des informations sur le réseau
 [Link] : pour localiser un serveur DHCP
 Limites
 Non fiable et non connecté comme UDP

65
Multicast UDP en Java
 Classe [Link]
 Spécialisation de DatagramSocket
 Constructeurs : identiques à ceux de DatagramSocket
 public DatagramSocket() throws SocketException
 Crée une nouvelle socket en la liant à un port quelconque libre
 Exception levée en cas de problème (a priori il doit pas y en avoir)
 public DatagramSocket(int port)
throws SocketException
 Crée une nouvelle socket en la liant au port précisé par le
paramètre port : c'est le port qui identifie le groupe de multicast
 Exception levée en cas de problème

66
Multicast UDP en Java
 Classe [Link] (suite)
 Gestion des groupes
 public void joinGroup(InetAddress mcastaddr)
throws IOException
 Rejoint le groupe dont l'adresse IP multicast est passée en
paramètre
 L'exception est levée en cas de problèmes, notamment si l'adresse
IP n'est pas une adresse IP multicast valide
 public void leaveGroup(InetAddress mcastaddr)
throws IOException
 Quitte un groupe de multicast
 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
67
Multicast UDP en Java
 Classe [Link] (suite)
 Emission/réception de données
 On utilise les services send() et receive() avec des
paquets de type DatagramPacket tout comme avec une
socket UDP standard
 Exemple, exécution dans l'ordre :
 Connexion à un groupe
 Envoi d'un paquet
 Réception d'un paquet
 Quitte le groupe

68
Multicast UDP en Java
 Exemple de communication via socket multicast UDP
// adresse IP multicast du groupe
InetAddress group = [Link]("[Link]");

// socket UDP multicast pour communiquer avec groupe [Link]:4000


MulticastSocket socket = new MulticastSocket(4000);

// données à envoyer
byte[] data = (new String(''youpi'')).getBytes();

// paquet à envoyer (en précisant le couple @IP/port du groupe)


DatagramPacket packet =
new DatagramPacket(data, [Link], group, 4000);

// on joint le groupe
[Link](group);

69
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

70
Concurrence dans une application

Threads Java

71
Concurrence
 Par principe, les éléments distants
communiquants sont actifs en parallèle
 Plusieurs processus concurrents
 Avec processus en pause lors d'attente de messages
 Exemple de flux d'exécution pour notre exemple
de client/serveur précédent

temps

72
Sockets TCP – gestion plusieurs clients
 Particularité coté serveur en TCP
 Une socket d'écoute sert à attendre les connexions des
clients
 A la connexion d'un client, une socket de service est
initialisée pour communiquer avec ce client
 Communication avec plusieurs clients pour le serveur
 Envoi de données à un client
 UDP : on précise l'adresse du client dans le paquet à envoyer
 TCP : 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
73
Sockets TCP – gestion plusieurs clients
 Communication avec plusieurs clients (suite)
 Contrainte
 Lecture sur une socket : opération bloquante
 Tant que des données ne sont pas reçues
 Attente de connexion : opération bloquante
 Jusqu'à la prochaine connexion d'un client distant
 Avec un seul flot d'exécution (processus/thread)
 Si ne sait pas quel est l'ordonnancement des arrivées des données
des clients ou de leur connexion au serveur
 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
74
Sockets TCP – gestion plusieurs clients
 Boucle de fonctionnement général d'un serveur
pour gérer plusieurs clients
 while(true)
socketClient = acceptConnection()
newThread(socketClient)
 Exemple
avec 2
clients ->

75
Gestion plusieurs clients
 Java offre nativement un mécanisme permettant
de gérer des flux d'exécution parallèle
 Les threads
 Rappel différence processus/thread
 Le processus est créé comme une copie d'un processus
existant
 Deux processus distincts avec leur mémoire propre
 Le thread s'exécute au sein d'un processus existant
 Nouveau flux d'exécution interne
 Partage des données du processus

76
Threads en Java
 Pour créer et lancer un nouveau thread, 2 modes
 Etendre la classe [Link]
 Redéfinir la méthode public void run()
 Qui contient la séquence de code qu'exécutera le thread
 Pour lancer le thread
 Instancier normalement la classe définie
 Appeler ensuiter la méthode start() sur l'objet créé
 Implémenter l'interface [Link]
 Définir la méthode public void run() de cette interface
 Qui contient la séquence de code qu'exécutera la thread
 Pour lancer le thread
 Instancier normalement la classe définie
 Créer une instance de la classe Thread en passant cet objet en
paramètre
 Lancer la méthode start() du thread instancié 77
Thread Java – exemple
 Classe CalculFactoriel calcule un factoriel et affiche
le résultat à l'écran
 Via un thread à part
public class CalculFactoriel extends Thread {

protected int nb;

public void run(){


int res = 1;
for (int i=1; i<=nb; i++)
res = res * i;
[Link](''factoriel de ''+nb+''=''+res);
}

public CalculFactoriel(int nb) {


[Link] = nb; }
}
78
Thread Java – exemple
 Lancement du calcul des factoriels de 1 à 10 en
parallèle
 ...
CalculFactoriel cf;
for (int i=10; i >= 1; i--) {
cf = new CalculFactoriel(i);
[Link]();
}
...
 Deux phases pour lancer un calcul
 On instantie normalement la classe CalculFactoriel
 On appelle la méthode start() sur l'objet créé
 La séquence d'instructions de la méthode run() de la classe
CalculFactoriel est exécutée via un nouveau thread créé
79
Thread Java – variante exemple
 Même exemple mais sans spécialiser la classe Thread
 Implémentation de l'interface Runnable
public class CalculFactoriel implements Runnable {

protected int nb;

public void run(){


int res = 1;
for (int i=1; i<=nb; i++)
res = res * i;
[Link](''factoriel de ''+nb+''=''+res);
}

public CalculFactoriel(int nb) {


[Link] = nb; }
}

80
Thread Java – variante exemple
 Lancement des threads
 ...
CalculFactoriel cf;
for (int i=10; i >= 1; i--) {
cf = new CalculFactoriel(i);
(new Thread(cf)).start();
}
...
 On lance un Thread générique qui exécutera la
méthode run() de l'objet de type Runnable passé en
paramètre du constructeur

81
Thread Java – création
 2 méthodes pour créer et exécuter un thread
 Laquelle choisir ?
 A priori peu de différence
 Sauf dans le cas où la classe doit hériter d'une autre
classe
 Cas typique d'une applet
 public MaClasse extends Applet implements Runnable
 Doit alors forcément utiliser l'interface Runnable

82
Thread Java – résultat exemple
 (un) résultat de l'exécution du programme
 factoriel de 10=3628800
factoriel de 9=362880
factoriel de 8=40320
factoriel de 7=5040
factoriel de 6=720
factoriel de 5=120
factoriel de 4=24
factoriel de 3=6
factoriel de 2=2
factoriel de 1=1
 Les résultats des calculs sont affichés dans l'ordre de
leur lancement
 Pourtant les calculs de petites valeurs sont normalement plus
courts car moins de passages dans la boucle ...
83
Ordonnancement des threads
 Ordonnancement des processus/threads
 Sur une machine, nombre de flots d'exécution en réel
parallélisme = nombre de processeurs
 Les processus/threads doivent partager les supports
d'exécution pour s'exécuter
 Pour simuler un parallélisme d'exécution avec un seul
processeur
 Un processus/thread n'est pas exécuté du début à la fin en une
seule étape
 Un processus/thread exécute une partie de ses instructions
pendant un temps donné avant de passer la main à un autre
processus
 Plus tard, il retrouvera la main et continuera son exécution
84
Ordonnancement des threads
 Dépendance thread/processus
 Un thread est créé par et dans un processus
 Selon le système d'exploitation, l'ordonnancement se fait
 Uniquement au niveau processus
 Le système s'occupe de gérer uniquement le parallélisme des processus
 Un processus gère en interne l'ordonnancement de ses propres threads
 Au niveau de tous les thread et processus
 Les threads des processus et les processus sont ordonnancés par le
système
 Approche mixte
 L'ordonnancement se fait au niveau processus mais certains threads
particuliers peuvent être ordonnancés par le système au même niveau
que les processus

85
Ordonnancement des threads
 Deux types d'ordonnancement par le système (ou
par le processus pour ordonnancer ses threads)
 Préemptif
 Le système interrompt l'exécution des processus/threads pour
partager l'accès au processeur
 Le système décide quel est le prochain processus/thread qui
continuera son exécution
 Coopératif
 Un processus/thread ne libère le processeur que
 Quand il est bloqué momentanément (entrée/sortie ...)
 De sa propre initiative
 Le système décide alors quel est le prochain processus/thread qui
continuera son exécution

86
Ordonnancement des threads Java
 Ordonnancement des threads en Java
 Exécution d'une machine virtuelle Java
 Via un processus du système d'exploitation
 Qui exécute plusieurs threads Java
 Le thread principal
 Correspondant au static void main(String argv[])
 Les threads créés par le programme
 Les threads gérant l'interface graphique
 Garbage collector ...
 Particularité de Java
 Langage multi-plateformes (windows, linux, solaris, ...)
 L'ordonnancement des processus/threads dépend du
système d'exploitation
87
Ordonnancement des threads Java
 Principe fondamental
 On ne doit pas se baser sur un modèle
d'ordonnancement particulier pour développer une
application multi-threadée en Java
 Par principe, on considèrera le modèle le plus
contraignant
 Généralement c'est l'ordonnancement coopératif des
threads Java
 Si on veut un parallélisme « correct », tout thread doit
relacher la main de temps en temps
 Sans oublier qu'en cas de synchronisation/communication
obligatoire entre threads, il faut que tout thread ait la main
régulièrement
88
Ordonnancement des threads
 Les threads peuvent avoir des priorités différentes
 Un thread plus prioritaire a la main en priorité
 Si un thread de plus haute priorité que le thread courant actif veut la
main, il la récupère alors de suite
 Toujours via un ordonnancement préemptif
 Accès aux priorités, méthodes de la classe Thread
 public int getPriority() : retourne le niveau de priorité du
thread
 public void setPriority(int priority) : change le
niveau de priorité du thread
 Trois constantes de la classe Thread pour définir les priorités
 MAX_PRIORITY : niveau de priorité maximal possible (10)
 MIN_PRIORITY : niveau de priorité minimal possible (1)
 NORM_PRIORITY : niveau de priorité par défaut (5)
89
Ordonnancement des threads Java
 Retour sur l'exemple du calcul de factoriel
 Une fois que la méthode run() d'un thread est commencée,
on doit donc supposer que ce thread garde au pire le
processeur jusqu'à la fin de sa méthode run()
 Pour avoir un meilleur parallélisme, il faut qu'un thread passe
la main à un autre thread de temps en temps
 Dans la classe [Link]
 public static void yield()
 Le thread s'interrompt et passe la main à un autre thread
 Modification de l'exemple
 Ajout d'un yield() après chaque calcul dans run()
for (int i=1; i<=nb; i++) {
res = res * i;
[Link](); }
90
Thread Java – nouveau résultat exemple
 (un) résultat d'exécution de l'exemple après la modification
 factoriel de 1=1
factoriel de 2=2
factoriel de 3=6
factoriel de 4=24
factoriel de 5=120
factoriel de 6=720
factoriel de 7=5040
factoriel de 8=40320
factoriel de 9=362880
factoriel de 10=3628800
 Bien que lancés en dernier, les calculs les plus courts se
terminent en premier
 Ordonnancement plus « naturel » que le précédent
 Correspond à ce que l'on aurait avec un parrallélisme physique complet
 Mais aurait pu avoir un ordre moins « parfait »
 1, 2, 4, 3, 5, 7, 6, 8, 9, 10 par exemple 91
Ordonnancement des threads
 Un thread passe la main à un autre dès qu'il est bloqué ou
en attente, c'est-à-dire dans les cas suivants
 Il est bloqué en attente sur une entrée/sortie (flux)
 Il est bloqué sur l'accès à un objet synchronisé
 Il se met en attente avec un wait()
 Il fait une pause pendant une certaine durée avec un sleep()
 Il a executé un yield() pour céder explicitement la main
 Il se met en attente de la terminaison d'un autre thread avec un join()
 Il se termine
 Un thread de plus haute priorité demande la main
 Une application Java se termine quand
 Le main() et tous les run() de tous les threads créés sont
terminés
92
Interactions entre threads
 Les threads sont des objets comme les autres
 Ils possèdent des références sur d'autres objets
 Un thread peut appeler des méthodes sur ces objets
 On peut appeler des méthodes sur le thread
 Communication/interaction possible via ces objets ou les
méthodes du thread
 Avec mécanisme possible d'accès en exclusion mutuelle
 Relations entre les cycles de vie des threads
 Un thread peut lancer un autre thread
 Un thread peut attendre qu'un ou plusieurs threads se
terminent
 Un thread peut se bloquer et attendre d'être réveillé par un
autre thread
93
Interactions entre threads
 Communication par objet partagé
 Les threads s'exécutent dans la même machine virtuelle, dans le
même espace mémoire
 Accès possible aux mêmes objets
 Modification de l'exemple précédent pour ne plus afficher les résultats
mais les stocker dans un tableau auquel tous les threads ont accès

public class CalculFactorial


{
protected int[] tab;
protected int nb;

public void run(){


int res = 1;
for (int i=1; i<=nb; i++)
res = res * i;
//enregistre le résultat dans tableau
tab[nb - 1] = res;
} 94
Interactions entre threads
 Modification du constructeur pour passer le tableau
partagé en paramètre
public CalculFactoriel(int nb, int[] tab) {
[Link] = nb;
[Link] = tab; }

 Nouveau lancement des threads dans le thread principal


int[] resultats = new int[10];
CalculFactoriel cf;
for (int i=10; i >= 1; i--) {
cf = new CalculFactoriel(i, resultats);
(new Thread(cf)).start();
}
 Avant d'afficher les résultats : doit attendre que tous les
threads soient terminés
95
Interactions entre threads
 Un thread peut attendre qu'un thread se termine via la
méthode join() appellée sur le thread dont on attend la fin
 Pour l'exemple, le thread principal doit attendre que tous les
threads lancés soient terminés
int[] resultats = new int[10];
CalculFactoriel[] tabCF = new CalculFactoriel[10];
CalculFactoriel cf;
// lance les threads
for (int i=10; i>=1; i--) {
cf = new CalculFactoriel(i, resultats);
tabCF[i-1] = cf;
[Link](); }

// attend la fin de chaque thread


for (int i=0; i < 10; i++) {
try { tabCF[i].join(); }
catch(InterruptedException e) {[Link](e);}
}
96
Interactions entre threads
 Modification exemple (suite)
 Une fois la boucle avec les join() passée, on est certain que
tous les threads de calcul sont finis
 Peut alors afficher les résultats

for (int i=1; i<=10; i++)


[Link](" factoriel de "
+i+"="+resultats[i-1]);
 Trois méthodes de la classe Thread pour attendre la
terminaison d'un thread
 public void join() : attend la fin du thread
 public void join(int milli) : attend au plus milli
millisecondes
 public void join(int milli, int nano) : attend au
plus milli millisecondes et nano nanosecondes

97
Interactions entre threads
 Méthodes join() (suite)
 Les 3 méthodes join() peuvent lever l'exception
[Link]
 Si exception levée : signifie que l'attente du thread a été
interrompue et qu'il reprend son activité
 Pour arrêter l'attente d'un thread : appel de la méthode
public void interrupt() sur le thread
 Interrogation sur l'état d'un thread
 public boolean isInterrupted() : retourne vrai si le
thread a été interrompu dans son attente
 public boolean isAlive() : retourne vrai si le thread est
en vie (démarré mais pas encore terminé)

98
Synchronisation sur objets
 Tableau partagé de l'exemple
 Chaque thread écrit dans sa case du tableau
 Pas de risque de conflit dans ce cas
 Mais attention aux accès concurrents à des objets
partagés
 Peut conduire à des incohérences
 Si 2 threads modifient en même temps le même objet par ex.
 En pratique, sur une machine mono-processeur, un seul thread
est actif en même temps
 Mais un thread peut commencer une méthode, passer la main à
un autre thread qui modifiera l'état de l'objet
 Le premier thread reprend alors l'exécution de la méthode avec un
état différent et incohérent
99
Synchronisation sur objets
 Exemple de code pouvant poser problème
public class CalculPuissance {

protected int puissance = 1;

public int calculPuissance(int val) {


int res = val;
for (int i=1; i<puissance; i++)
res = res * val;
return res;
}
public setPuissance(int p) {
puissance = p;
} }
 Doit prendre en compte le cas d'ordonnancement le plus
mauvais
 Ordonnancement préemptif des threads dans ce cas précis
100
Synchronisation sur objets
 Exemple (suite)
 Lancement d'un calcul de puissance
CalculPuissance cp = new CalculPuissance();
... // passage de la référence de cp à d'autres threads
[Link](3);
int resultat = [Link](2);
[Link](" puissance 3 de 2 = "+resultat);
 Problème
 Si pendant l'exécution de calculPuissance(), un autre thread
appelle setPuissance(), le calcul sera faux !
 Exemple avec un autre thread appelant setPuissance() avec la
valeur 4 pendant l'exécution de calculPuissance()

puissance 3 de 2 = 16
 Valeur 16 renvoyée au lieu de 8 ...
 Car l'attribut puissance est passé à la valeur 4 au milieu de la boucle
101
Synchronisation sur objets
 Primitive synchronized
 Elle s'applique sur un objet (n'importe lequel)
 Exclusion mutuelle sur une séquence de code
 Il est impossible que 2 threads exécutent en même temps une
section de code marquée synchronized pour un même objet
 Sauf si un thread demande explicitement à se bloquer avec
un wait()
 Deux utilisations de synchronized
 Sur la méthode d'une classe (s'applique à tout son code pour un
objet de cette classe)
public synchronized int calculPuissance(int val)
 Sur un objet quelconque
synchronized(cp) {
// zone de code protégée sur l'objet cp
}
102
Synchronisation sur objets
 Retour sur l'exemple
 Suppression de l'erreur potentielle de calcul
 On rajoute synchronized dans la définition des méthodes
public synchronized int calculPuissance(int val) {
int res = val;
for (int i=1; i<puissance; i++)
res = res * val;
return res;
}
public synchronized setPuissance(int p) {
puissance = p;
}
 Il est alors impossible qu'un thread modifie la valeur de
puissance lorsqu'un calcul est en cours
 Car synchronized interdit que setPuissance() soit exécutée
tant que l'exécution d'un calculPuissance() n'est pas finie
103
Synchronisation sur objets
 Exemple du calcul de puissance (suite)
 Il reste un problème potentiel de cohérence, pour la
séquence de lancement du calcul
CalculPuissance cp = new CalculPuissance();
... // passage de la référence de cp à d'autres threads
[Link](3);
// un autre thread peut appeler ici setPuissance
// avec la valeur de 4 avant que le calcul soit lancé
[Link](4); // exécuté dans un autre thread
int resultat = [Link](2);
[Link](" puissance 3 de 2 = "+resultat);

 Le résultat affiché sera là encore 16 au lieu de 8


 Calcul effectué correctement cette fois mais ce n'est pas celui qui
était voulu par le thread !
104
Synchronisation sur objets
 Exemple du calcul de puissance (suite)
 Pour éviter ce problème, il faut protéger la séquence de
positionnement de la puissance puis du calcul
CalculPuissance cp = new CalculPuissance();
int resultat;

... // passage de la référence de cp à d'autres threads

synchronized(cp) {
[Link](3);
resultat = [Link](2); }
[Link](" puissance 3 de 2 = "+resultat);
 Avec ce code, il est impossible qu'un autre thread exécute sur
l'objet cp la méthode setPuissance() entre le
setPuissance() et le calculPuissance()
105
Synchronisation sur objets
 Exemple du calcul de puissance (fin)
 Avec ce nouveau code, il y a trois sections de code protégées sur
l'objet cp, avec un accès en exécution en exclusion mutuelle
 Le code de la méthode setPuissance()
 Le code de la méthode calculPuissance()
 La séquence
synchronized(cp) {
[Link](3);
resultat = [Link](2); }
 Si un thread est en train d'exécuter une de ces 3 sections
protégées sur l'objet cp
 Aucun autre thread ne peut exécuter une des 3 sections protégées tant
que le premier thread n'a pas fini d'exécuter sa section protégée
 Note
 La séquence de code inclue dans le synchronized(cp) {...}
ne contient que des références à cp mais ce n'est pas une obligation
106
Synchronisation sur objets
 Pour des variables de types primitifs (int ...) en
accès concurrent, on utilise volatile
 Le problème n'est pas forcément dans la possible
incohérence en lecture/écriture
 Mais vient du fonctionnement des threads
 Localement, un thread gère une copie d'une variable partagée
 La déclarer comme volatile force à garder la cohérence entre
la copie locale et la variable partagée
 Exemple
protected volatile int nb;

public int incNb() { return nb++; }


 Assure que si un thread exécute incNb() il utilise la valeur
de nb la plus à jour
107
Synchronisation entre threads
 Problème courant
 Besoin d'un point de synchronisation entre threads
 Un thread fait un calcul et un autre thread attend que le résultat de ce
calcul soit disponible pour continuer son exécution
 Solution basique : déclarer un booléen available qui sera mis à vrai quand
le résultat est disponible
public class ThreadCalcul extends Thread {

protected boolean available;


protected int result;

public boolean getAvailable() {


return available;}

public int getResult() { return result; }

public void run() {


// faire calcul, mettre result à jour et préciser
// que le résultat est disponible
available = true;
// continuer l'exécution du thread } } 108
Synchronisation entre threads
 Du coté du thread attendant le résultat
 Solution basique
 Vérifier en permanence la valeur de available

ThreadCalcul calcul;
// calcul lancé avec référence sur bon thread
...
// boucle attendant que le résultat soit disponible
while (![Link]()) {
// fait rien, juste attendre que available change
}
int res = [Link]();
 Problème
 Attente active
 Le thread qui fait la boucle peut ne jamais lacher la main
 L'autre thread ne peut donc pas faire le calcul !
109
Synchronisation entre threads
 Pour éviter problème de l'attente active
 Soit le thread passe la main avec un yield() dans la
boucle
 Mais reste très actif pour pas grand chose ...
 Dans la boucle, le thread peut faire des pauses
 Pause d'un thread : sleep dans la classe Thread
 public static void sleep(long millis[, int nanos])
throws InterruptedException
 Le thread courant fait une pause de millis millisecondes [et
nanos nanosecondes]
 Pendant cette pause, un autre thread peut alors prendre la main
 L'exception InterruptedException est levée si le thread
a été interrompu pendant sa pause
110
Synchronisation entre threads
 Modification de la boucle d'attente avec un sleep
while (![Link]()) {
try {
[Link](100); }
catch ([Link] e) { ... }
}
}
int res = [Link]();
 Problèmes
 Combien de temps doit durer la pause ?
 On est pas averti dès que le calcul est fini
 Solution idéale
 Se mettre en pause et être réveillé dès que le résultat est disponible
 Programmation en mode « réactif » : réaction/réveil sur
événements, jamais d'attente ou de vérification active
111
Synchronisation entre threads
 Synchronisation par moniteur
 Dans une section de code protégée par un synchronized,
trois primitives de synchronisation sur un objet
 public void wait() throws InterruptedException
 Le thread se bloque
 Il permet alors à un autre thread d'exécuter une séquence de code
protégée sur l'objet
 C'est le cas où un thread peut exécuter une séquence protégée alors
qu'un autre thread n'a pas terminé son exécution
 Il existe 2 variantes permettant de rester bloquer au plus un certain temps
 public void notify()
 Débloque un thread bloqué (pris au hasard si plusieurs thread
bloqués) sur un wait() sur cet objet
 public void notifyAll()
 Débloque tous les threads bloqués sur un wait() sur cet objet
112
Synchronisation entre threads
 Synchronisation par moniteur
 wait(), notify() et notifyAll() sont des
méthodes de la classe [Link]
 Application à l'exemple précédent
 Thread faisant le calcul
public class ThreadCalcul extends Thread {

protected boolean available;


protected int result;

public synchronized boolean getAvailable() {


return available;
}

113
Synchronisation entre threads
 Thread faisant le calcul (suite)
public void run() {
// faire le calcul, mettre result à jour et préciser
// que le résultat est disponible
synchronized(this) {
available = true;
[Link]();
}// continuer l'exécution du thread }

// opération de récupération du résultat


// si pas encore disponible, on attend qu'il le soit
public synchronized getResult() {
while (![Link])
try { [Link](); }
catch (InterruptedException e) {... } } }
 Thread attendant le résultat
int res = [Link]();
 Si le résultat n'est pas disponible, on sera bloqué en attendant 114
le notify executé par le thread de calcul
 Thread
Résumé sur les threads
 Objet ayant son propre flot d'exécution
 Etats, opérations associés aux threads
 Créé : instantiation standard d'un objet Java
 Démarré et actif : après appel de la méthode start()
 En pause : méthode sleep()
 Bloqué sur un objet synchronisé : méthode wait()
 Réveillé par un notify() sur le même objet
 Attente de la terminaison d'un autre thread : méthode join()
 Interrompu pendant une pause sur un wait(), sleep() ou un
join() par l'appel de interrupt()
 L'exception InterruptedException est levée
 Terminé : arrivé à la fin de sa méthode run()
115
Résumé sur les threads
 Pourquoi et quand utiliser des threads ?
 Sur une machine mono-processeur pas de gain de
performances a priori en parallélisant
 Certains cas imposent des threads
 Pour entreés/sorties, les lectures sont généralement bloquantes
 On dédie un ou plusieurs threads aux réceptions pour gérer des
réceptions multiples, ainsi que d'éviter de bloquer le programme
 Les threads de lecture communiquent par synchronisation/objets
communs avec les autres threads
 Les interfaces graphiques utilisent également des threads,
généralement de hautes priorités
 Peut gérer des événements graphiques (clics ...) venant de l'utilisateur
alors que le programme effectue d'autres traitements
 Peut aussi être une meilleure structuration du
fonctionnement de l'application
116
Résumé sur les threads
 Points délicats en programmation multi-threadée
 Eviter les famines : un thread n'a jamais la main
 Ne jamais utiliser d'attente active
 S'assurer qu'un thread passe la main suffisamment
 Ne pas avoir des threads de haute priorité beaucoup trop actifs
 Eviter les interblocages
 Un thread T1 attend le résultat d'un thread T2 qui attend lui le
résultat du thread T1
 Si chacun se bloque sur un wait(), aucun ne pourra faire le
notify() réveillant l'autre
 Interblocage peut se passer via une chaîne de plusieurs threads
interdépendants
 Pas toujours simple à détecter si dépendances complexes

117
Résumé sur les threads
 Problèmes de performances en cas d'utilisation
massive de threads
 Relativement coûteux de créer un thread à chaque requête
 En temps de création et de destruction par le garbage collector
 Pool de thread : ensemble de threads déjà créés et qui peuvent
être réutilisés pour traiter de nouvelles requêtes
 La méthode run() est une boucle qui traite une requête à chaque
passage
 Avec la synchronisation (wait/notify) on peut relancer un passage
dans la boucle pour traiter une nouvelle requête
 Attention à la taille du pool selon le nombre de requêtes simultanées à
traiter
 Eviter de définir des méthodes en synchronized prenant un
temps relativement long à s'exécuter et étant souvent
appelées
118

Vous aimerez peut-être aussi