Cours 2 Sockets
Cours 2 Sockets
Cours 2 Sockets
Eric Cariou
Eric.Cariou@univ-pau.fr
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 : 192.129.12.34
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
192.129.12.34:80 : accès au serveur Web tournant sur la machine
d'adresse IP 192.129.12.34
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
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 java.net
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 (''192.12.23.24'') 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;
23
Sockets UDP Java – exemple coté serveur
DatagramSocket socket;
DatagramPacket packet;
25
Sockets UDP en Java – exemple suite
Réception réponse du serveur, coté client
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
System.out
Sortie standard, flux de type PrintStream
System.out.println(''nombre = ''+nb);
System.err
Sortie d'erreur strandard, flux de type PrintStream
System.in
Entrée standard, flux de type InputStream
while ((c = (char)System.in.read()) != 'z')
System.out.print(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 java.io
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 java.util.zip
Compression données : GZIPInputStream, ZipInputStream ...
Vérification intégrité données (CRC) : CheckedInputStream ...
Package javax.crypto
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 = .... ;
output.writeObject(pers);
Pour pouvoir envoyer un objet dans un flux
Sa classe doit implémenter l'interface
java.io.Serializable
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 java.io.IOException
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 test.bin
FileOutputStream fileOut=
new FileOutputStream(''test.bin'');
ObjectOutputStream objOut =
new ObjectOutputStream(fileOut);
// peut maintenant enregistrer tout objet dans test.bin 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 entiers.bin
FileOutputStream ficOut =
new FileOutputStream("entiers.bin");
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);
objectStream.writeObject(object);
byte[] byteArray = byteStream.toByteArray();
En lecture : conversion de byte[] en Object
ByteArrayInputStream byteStream =
new ByteArrayInputStream(byteArray);
ObjectInputStream objectStream =
new ObjectInputStream(byteStream);
object = objectStream.readObject();
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 java.net 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 = InetAddress.getByName("scinfr222");
55
Sockets TCP Java – exemple coté client
Coté client (suite)
56
Sockets TCP Java – exemple coté serveur
// serveur positionne sa socket d'écoute sur le port local 7777
ServerSocket serverSocket = new ServerSocket(7777);
57
Sockets TCP Java – exemple coté serveur
Coté serveur (suite)
// affiche les coordonnées du client qui vient de se connecter
System.out.println(" ca vient de : "
+socket.getInetAddress()+":"+socket.getPort());
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 224.0.0.0 et 239.255.255.255
Classe D
Adresses entre 225.0.0.0 et 238.255.255.255 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
224.0.0.12 : pour localiser un serveur DHCP
Limites
Non fiable et non connecté comme UDP
65
Multicast UDP en Java
Classe java.net.MulticastSocket
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 java.net.MulticastSocket (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 java.net.MulticastSocket (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 = InetAddress.getByName("228.5.6.7");
// données à envoyer
byte[] data = (new String(''youpi'')).getBytes();
// on joint le groupe
socket.joinGroup(group);
69
Multicast UDP en Java
Exemple (suite)
// on envoie le paquet
socket.send(packet);
// traite le résultat
...
// quitte le groupe
socket.leaveGroup(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 java.lang.Thread
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 java.lang.Runnable
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 {
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 java.lang.Thread
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;
Thread.yield(); }
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
97
Interactions entre threads
Méthodes join() (suite)
Les 3 méthodes join() peuvent lever l'exception
java.lang.InterruptedException
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 {
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
cp.setPuissance(3);
// un autre thread peut appeler ici setPuissance
// avec la valeur de 4 avant que le calcul soit lancé
cp.setPuissance(4); // exécuté dans un autre thread
int resultat = cp.calculPuissance(2);
System.out.println(" puissance 3 de 2 = "+resultat);
synchronized(cp) {
cp.setPuissance(3);
resultat = cp.calculPuissance(2); }
System.out.println(" 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) {
cp.setPuissance(3);
resultat = cp.calculPuissance(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;
ThreadCalcul calcul;
// calcul lancé avec référence sur bon thread
...
// boucle attendant que le résultat soit disponible
while (!calcul.getAvailable()) {
// fait rien, juste attendre que available change
}
int res = calcul.getResult();
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 (!calcul.getAvailable()) {
try {
Thread.sleep(100); }
catch (java.lang.InterruptedException e) { ... }
}
}
int res = calcul.getResult();
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 java.lang.Object
Application à l'exemple précédent
Thread faisant le calcul
public class ThreadCalcul extends Thread {
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;
this.notifyAll();
}// continuer l'exécution du thread }
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