systèmes distribués sockets tcp/udp et leur mise en œuvre

118
1 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 [email protected]

Upload: others

Post on 23-Jul-2022

3 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: Systèmes distribués Sockets TCP/UDP et leur mise en œuvre

1

Systèmes distribués

Sockets TCP/UDP et leurmise en œuvre en Java

Eric Cariou

Université de Pau et des Pays de l'AdourDépartement Informatique

[email protected]

Page 2: Systèmes distribués Sockets TCP/UDP et leur mise en œuvre

2

Plan1. Sockets UDP2. Les flux Java3. Sockets TCP4. Multicast IP5. Concurrence

1. Les threads Java2. Synchronisation en Java

Page 3: Systèmes distribués Sockets TCP/UDP et leur mise en œuvre

3

Rappel sur les réseaux TCP ou UDP

Communication entre systèmes aux extrémités Pas de visibilité des systèmes intermédiaires

Physique

Liaison

IP

TCP/UDP

Application

Physique

Liaison

IP

TCP/UDP

Application

Physique

Liaison

IP

Communication d’extrémitéà extrémité

Physique

Liaison

IP

TCP/UDP

Application

Physique

Liaison

IP

TCP/UDP

Application

Physique

Liaison

IP

Communication d’extrémitéà extrémité

Page 4: Systèmes distribués Sockets TCP/UDP et leur mise en œuvre

4

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

Page 5: Systèmes distribués Sockets TCP/UDP et leur mise en œuvre

5

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

Page 6: Systèmes distribués Sockets TCP/UDP et leur mise en œuvre

6

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

machine distante : c'est-à-dire avec une application distante

Page 7: Systèmes distribués Sockets TCP/UDP et leur mise en œuvre

7

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 portprécis : port d'écoute

Dissymétrie de la communication/connexion Le client initie la connexion ou la communication

Page 8: Systèmes distribués Sockets TCP/UDP et leur mise en œuvre

8

Sockets UDP

Page 9: Systèmes distribués Sockets TCP/UDP et leur mise en œuvre

9

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

Page 10: Systèmes distribués Sockets TCP/UDP et leur mise en œuvre

10

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

Page 11: Systèmes distribués Sockets TCP/UDP et leur mise en œuvre

11

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)

Page 12: Systèmes distribués Sockets TCP/UDP et leur mise en œuvre

12

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

Page 13: Systèmes distribués Sockets TCP/UDP et leur mise en œuvre

13

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

Page 14: Systèmes distribués Sockets TCP/UDP et leur mise en œuvre

14

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

Page 15: Systèmes distribués Sockets TCP/UDP et leur mise en œuvre

15

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

Page 16: Systèmes distribués Sockets TCP/UDP et leur mise en œuvre

16

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

Page 17: Systèmes distribués Sockets TCP/UDP et leur mise en œuvre

17

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

Page 18: Systèmes distribués Sockets TCP/UDP et leur mise en œuvre

18

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

Page 19: Systèmes distribués Sockets TCP/UDP et leur mise en œuvre

19

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é

Page 20: Systèmes distribués Sockets TCP/UDP et leur mise en œuvre

20

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 lasocket distante qui a émis le paquet

Page 21: Systèmes distribués Sockets TCP/UDP et leur mise en œuvre

21

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ù

Page 22: Systèmes distribués Sockets TCP/UDP et leur mise en œuvre

22

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

Page 23: Systèmes distribués Sockets TCP/UDP et leur mise en œuvre

23

Sockets UDP Java – exemple coté client InetAddress adr;

DatagramPacket packet;DatagramSocket socket;

// adr contient l'@IP de la partie serveuradr = InetAddress.getByName("scinfr222");

// données à envoyer : chaîne de caractèresbyte[] 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, data.length, adr, 7777);

// création d'une socket, sans la lier à un port particuliersocket = new DatagramSocket();

// envoi du paquet via la socketsocket.send(packet);

Page 24: Systèmes distribués Sockets TCP/UDP et leur mise en œuvre

24

Sockets UDP Java – exemple coté serveur DatagramSocket socket;

DatagramPacket packet;

// création d'une socket liée au port 7777DatagramSocket socket = new DatagramSocket(7777);

// tableau de 15 octets qui contiendra les données reçuesbyte[] data = new byte[15];

// création d'un paquet en utilisant le tableau d'octetspacket = new DatagramPacket(data, data.length);

// attente de la réception d'un paquet. Le paquet reçu est placé dans// packet et ses données dans data.socket.receive(packet);

// récupération et affichage des données (une chaîne de caractères)String chaine = new String(packet.getData(), 0,

packet.getLength()); System.out.println(" recu : "+chaine);

Page 25: Systèmes distribués Sockets TCP/UDP et leur mise en œuvre

25

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 System.out.println(" ca vient de :

"+packet.getAddress()+":"+ packet.getPort());

// on met une nouvelle donnée dans le paquet // (qui contient donc le couple @IP/port de la socket coté client)packet.setData((new String("bien recu")).getBytes());

// on envoie le paquet au clientsocket.send(packet);

Page 26: Systèmes distribués Sockets TCP/UDP et leur mise en œuvre

26

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

// attente paquet envoyé sur la socket du clientsocket.receive(packet);

// récupération et affichage de la donnée contenue dans le paquetString chaine = new String(packet.getData(), 0,

packet.getLength());System.out.println(" recu du serveur : "+chaine);

Page 27: Systèmes distribués Sockets TCP/UDP et leur mise en œuvre

27

Critique sockets UDP Avantages

Simple à programmer (et à appréhender) Inconvénients

Pas fiable Ne permet d'envoyer que des tableaux de byte

Page 28: Systèmes distribués Sockets TCP/UDP et leur mise en œuvre

28

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)

Page 29: Systèmes distribués Sockets TCP/UDP et leur mise en œuvre

29

Flux Java

Page 30: Systèmes distribués Sockets TCP/UDP et leur mise en œuvre

30

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

Page 31: Systèmes distribués Sockets TCP/UDP et leur mise en œuvre

31

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

Page 32: Systèmes distribués Sockets TCP/UDP et leur mise en œuvre

32

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

Page 33: Systèmes distribués Sockets TCP/UDP et leur mise en œuvre

33

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

Page 34: Systèmes distribués Sockets TCP/UDP et leur mise en œuvre

34

Hiérarchie de flux Java Flux binaire, entrée

Page 35: Systèmes distribués Sockets TCP/UDP et leur mise en œuvre

35

Hiérarchie de flux Java Flux binaire, sortie

Page 36: Systèmes distribués Sockets TCP/UDP et leur mise en œuvre

36

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

Page 37: Systèmes distribués Sockets TCP/UDP et leur mise en œuvre

37

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

Page 38: Systèmes distribués Sockets TCP/UDP et leur mise en œuvre

38

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

Page 39: Systèmes distribués Sockets TCP/UDP et leur mise en œuvre

39

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

Page 40: Systèmes distribués Sockets TCP/UDP et leur mise en œuvre

40

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

Page 41: Systèmes distribués Sockets TCP/UDP et leur mise en œuvre

41

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

Page 42: Systèmes distribués Sockets TCP/UDP et leur mise en œuvre

42

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

Page 43: Systèmes distribués Sockets TCP/UDP et leur mise en œuvre

43

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

Page 44: Systèmes distribués Sockets TCP/UDP et leur mise en œuvre

44

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.binFileOutputStream ficOut =

new FileOutputStream("entiers.bin");

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

new DataOutputStream(ficOut);

// écriture des entiers de 10 à 15 dans le fichierfor(int i=10;i<16;i++)

dataOut.writeInt(i);

// fermeture des fluxdataOut.close();ficOut.close();

Page 45: Systèmes distribués Sockets TCP/UDP et leur mise en œuvre

45

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 entiers.bin FileInputStream ficIn =

new FileInputStream("entiers.bin");

// ouverture d'un flux de données en entrée à partir de ce fluxDataInputStream dataIn = new DataInputStream(ficIn);

// tant que des données sont disponibles, on lit des entierswhile(dataIn.available() > 0)

System.out.println(dataIn.readInt());

// fermeture des fluxdataIn.close();ficIn.close();

Page 46: Systèmes distribués Sockets TCP/UDP et leur mise en œuvre

46

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 ObjectByteArrayInputStream byteStream =

new ByteArrayInputStream(byteArray); ObjectInputStream objectStream =

new ObjectInputStream(byteStream);object = objectStream.readObject();

Page 47: Systèmes distribués Sockets TCP/UDP et leur mise en œuvre

47

Sockets TCP

Page 48: Systèmes distribués Sockets TCP/UDP et leur mise en œuvre

48

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

Page 49: Systèmes distribués Sockets TCP/UDP et leur mise en œuvre

49

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 leursocket

Page 50: Systèmes distribués Sockets TCP/UDP et leur mise en œuvre

50

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

Page 51: Systèmes distribués Sockets TCP/UDP et leur mise en œuvre

51

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

Page 52: Systèmes distribués Sockets TCP/UDP et leur mise en œuvre

52

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

Page 53: Systèmes distribués Sockets TCP/UDP et leur mise en œuvre

53

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

Page 54: Systèmes distribués Sockets TCP/UDP et leur mise en œuvre

54

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

Page 55: Systèmes distribués Sockets TCP/UDP et leur mise en œuvre

55

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");

// ouverture de connexion avec le serveur sur le port 7777Socket socket = new Socket(adr, 7777);

Page 56: Systèmes distribués Sockets TCP/UDP et leur mise en œuvre

56

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

// construction de flux objets à partir des flux de la socketObjectOutputStream output =

new ObjectOutputStream(socket.getOutputStream());ObjectInputStream input =

new ObjectInputStream(socket.getInputStream());

// écriture d'une chaîne dans le flux de sortie : c'est-à-dire envoi de // données au serveuroutput.writeObject(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 directementString chaine = (String)input.readObject();System.out.println(" recu du serveur : "+chaine);

Page 57: Systèmes distribués Sockets TCP/UDP et leur mise en œuvre

57

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 distantSocket socket = serverSocket.accept();

// connexion acceptée : récupère les flux objets pour communiquer// avec le client qui vient de se connecterObjectOutputStream output =

new ObjectOutputStream(socket.getOutputStream());ObjectInputStream input =

new ObjectInputStream(socket.getInputStream());

// attente les données venant du clientString chaine = (String)input.readObject();

System.out.println(" recu : "+chaine);

Page 58: Systèmes distribués Sockets TCP/UDP et leur mise en œuvre

58

Sockets TCP Java – exemple coté serveur Coté serveur (suite)

// affiche les coordonnées du client qui vient de se connecterSystem.out.println(" ca vient de : "

+socket.getInetAddress()+":"+socket.getPort());

// envoi d'une réponse au client output.writeObject(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 = input.readObject();if (obj instanceof String) chaine = (String)obj;if (obj instanceof Personne) pers = (Personne)obj;

Page 59: Systèmes distribués Sockets TCP/UDP et leur mise en œuvre

59

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

Page 60: Systèmes distribués Sockets TCP/UDP et leur mise en œuvre

60

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

Page 61: Systèmes distribués Sockets TCP/UDP et leur mise en œuvre

61

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

Page 62: Systèmes distribués Sockets TCP/UDP et leur mise en œuvre

62

Multicast IP

Page 63: Systèmes distribués Sockets TCP/UDP et leur mise en œuvre

63

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

Page 64: Systèmes distribués Sockets TCP/UDP et leur mise en œuvre

64

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

Page 65: Systèmes distribués Sockets TCP/UDP et leur mise en œuvre

65

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

Page 66: Systèmes distribués Sockets TCP/UDP et leur mise en œuvre

66

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

Page 67: Systèmes distribués Sockets TCP/UDP et leur mise en œuvre

67

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

Page 68: Systèmes distribués Sockets TCP/UDP et leur mise en œuvre

68

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

Page 69: Systèmes distribués Sockets TCP/UDP et leur mise en œuvre

69

Multicast UDP en Java Exemple de communication via socket multicast UDP

// adresse IP multicast du groupeInetAddress group = InetAddress.getByName("228.5.6.7");

// socket UDP multicast pour communiquer avec groupe 228.5.6.7:4000MulticastSocket socket = new MulticastSocket(4000);

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

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

new DatagramPacket(data, data.length, group, 4000);

// on joint le groupe socket.joinGroup(group);

Page 70: Systèmes distribués Sockets TCP/UDP et leur mise en œuvre

70

Multicast UDP en Java Exemple (suite)

// on envoie le paquetsocket.send(packet);

// attend un paquet en réponse socket.receive(packet);

// traite le résultat...// quitte le groupesocket.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

Page 71: Systèmes distribués Sockets TCP/UDP et leur mise en œuvre

71

Concurrence dans une application

Threads Java

Page 72: Systèmes distribués Sockets TCP/UDP et leur mise en œuvre

72

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

Page 73: Systèmes distribués Sockets TCP/UDP et leur mise en œuvre

73

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

Page 74: Systèmes distribués Sockets TCP/UDP et leur mise en œuvre

74

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

Page 75: Systèmes distribués Sockets TCP/UDP et leur mise en œuvre

75

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)

Exempleavec 2clients ->

Page 76: Systèmes distribués Sockets TCP/UDP et leur mise en œuvre

76

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

Page 77: Systèmes distribués Sockets TCP/UDP et leur mise en œuvre

77

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é

Page 78: Systèmes distribués Sockets TCP/UDP et leur mise en œuvre

78

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;System.out.println(''factoriel de ''+nb+''=''+res);

}

public CalculFactoriel(int nb) {this.nb = nb; }

}

Page 79: Systèmes distribués Sockets TCP/UDP et leur mise en œuvre

79

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);cf.start();

}...

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éé

Page 80: Systèmes distribués Sockets TCP/UDP et leur mise en œuvre

80

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;System.out.println(''factoriel de ''+nb+''=''+res);

}

public CalculFactoriel(int nb) {this.nb = nb; }

}

Page 81: Systèmes distribués Sockets TCP/UDP et leur mise en œuvre

81

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

Page 82: Systèmes distribués Sockets TCP/UDP et leur mise en œuvre

82

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

Page 83: Systèmes distribués Sockets TCP/UDP et leur mise en œuvre

83

Thread Java – résultat exemple (un) résultat de l'exécution du programme

factoriel de 10=3628800factoriel de 9=362880factoriel de 8=40320factoriel de 7=5040factoriel de 6=720factoriel de 5=120factoriel de 4=24factoriel de 3=6factoriel de 2=2factoriel 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 ...

Page 84: Systèmes distribués Sockets TCP/UDP et leur mise en œuvre

84

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

Page 85: Systèmes distribués Sockets TCP/UDP et leur mise en œuvre

85

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

Page 86: Systèmes distribués Sockets TCP/UDP et leur mise en œuvre

86

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

Page 87: Systèmes distribués Sockets TCP/UDP et leur mise en œuvre

87

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

Page 88: Systèmes distribués Sockets TCP/UDP et leur mise en œuvre

88

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

Page 89: Systèmes distribués Sockets TCP/UDP et leur mise en œuvre

89

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)

Page 90: Systèmes distribués Sockets TCP/UDP et leur mise en œuvre

90

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(); }

Page 91: Systèmes distribués Sockets TCP/UDP et leur mise en œuvre

91

Thread Java – nouveau résultat exemple (un) résultat d'exécution de l'exemple après la modification

factoriel de 1=1factoriel de 2=2factoriel de 3=6factoriel de 4=24factoriel de 5=120factoriel de 6=720factoriel de 7=5040factoriel de 8=40320factoriel de 9=362880factoriel 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

Page 92: Systèmes distribués Sockets TCP/UDP et leur mise en œuvre

92

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

Page 93: Systèmes distribués Sockets TCP/UDP et leur mise en œuvre

93

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

Page 94: Systèmes distribués Sockets TCP/UDP et leur mise en œuvre

94

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;

}

Page 95: Systèmes distribués Sockets TCP/UDP et leur mise en œuvre

95

Interactions entre threads Modification du constructeur pour passer le tableau

partagé en paramètre

public CalculFactoriel(int nb, int[] tab) {this.nb = nb;this.tab = 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

Page 96: Systèmes distribués Sockets TCP/UDP et leur mise en œuvre

96

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 threadsfor (int i=10; i>=1; i--) {

cf = new CalculFactoriel(i, resultats);tabCF[i-1] = cf;cf.start(); }

// attend la fin de chaque threadfor (int i=0; i < 10; i++) {

try { tabCF[i].join(); } catch(InterruptedException e) {System.err.println(e);}

}

Page 97: Systèmes distribués Sockets TCP/UDP et leur mise en œuvre

97

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++)System.out.println(" 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

Page 98: Systèmes distribués Sockets TCP/UDP et leur mise en œuvre

98

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éthodepublic 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é)

Page 99: Systèmes distribués Sockets TCP/UDP et leur mise en œuvre

99

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

Page 100: Systèmes distribués Sockets TCP/UDP et leur mise en œuvre

100

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

Page 101: Systèmes distribués Sockets TCP/UDP et leur mise en œuvre

101

Synchronisation sur objets Exemple (suite)

Lancement d'un calcul de puissanceCalculPuissance cp = new CalculPuissance();... // passage de la référence de cp à d'autres threadscp.setPuissance(3);int resultat = cp.calculPuissance(2);System.out.println(" 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

Page 102: Systèmes distribués Sockets TCP/UDP et leur mise en œuvre

102

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 }

Page 103: Systèmes distribués Sockets TCP/UDP et leur mise en œuvre

103

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

Page 104: Systèmes distribués Sockets TCP/UDP et leur mise en œuvre

104

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 threadscp.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 threadint resultat = cp.calculPuissance(2);System.out.println(" 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 !

Page 105: Systèmes distribués Sockets TCP/UDP et leur mise en œuvre

105

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) {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()

Page 106: Systèmes distribués Sockets TCP/UDP et leur mise en œuvre

106

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

Page 107: Systèmes distribués Sockets TCP/UDP et leur mise en œuvre

107

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

Page 108: Systèmes distribués Sockets TCP/UDP et leur mise en œuvre

108

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 disponiblepublic 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 disponibleavailable = true;// continuer l'exécution du thread } }

Page 109: Systèmes distribués Sockets TCP/UDP et leur mise en œuvre

109

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 disponiblewhile (!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 !

Page 110: Systèmes distribués Sockets TCP/UDP et leur mise en œuvre

110

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

Page 111: Systèmes distribués Sockets TCP/UDP et leur mise en œuvre

111

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

Page 112: Systèmes distribués Sockets TCP/UDP et leur mise en œuvre

112

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

Page 113: Systèmes distribués Sockets TCP/UDP et leur mise en œuvre

113

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 {

protected boolean available;protected int result;

public synchronized boolean getAvailable() {return available;

}

Page 114: Systèmes distribués Sockets TCP/UDP et leur mise en œuvre

114

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 disponiblesynchronized(this) {

available = true;this.notifyAll();

}// continuer l'exécution du thread }

// opération de récupération du résultat// si pas encore disponible, on attend qu'il le soitpublic synchronized getResult() {

while (!this.getAvailable) try { this.wait(); }

catch (InterruptedException e) {... } } } Thread attendant le résultat

int res = calcul.getResult(); Si le résultat n'est pas disponible, on sera bloqué en attendant

le notify executé par le thread de calcul

Page 115: Systèmes distribués Sockets TCP/UDP et leur mise en œuvre

115

Résumé sur les threads Thread

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

Page 116: Systèmes distribués Sockets TCP/UDP et leur mise en œuvre

116

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

Page 117: Systèmes distribués Sockets TCP/UDP et leur mise en œuvre

117

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

Page 118: Systèmes distribués Sockets TCP/UDP et leur mise en œuvre

118

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