• Aucun résultat trouvé

Leméga-serveur Lesserveursd’images Contexte Consignes

N/A
N/A
Protected

Academic year: 2022

Partager "Leméga-serveur Lesserveursd’images Contexte Consignes"

Copied!
6
0
0

Texte intégral

(1)

EXAMEN PROGRAMMATION RÉSEAU 15/05/2017 15

30

-18

30

Les seuls documents autorisés sont les documents « sur papier » ; à l’exclusion de la copie ou des brouillons des voisins.

Consignes

— Lire très attentivement tout le sujet.

— Il est tout à fait possible de répondre à une question sans avoir répondu à toutes les questions précédentes et aussi d’utiliser les méthodes des questions précédentes même si on n’a pas donné leur code.

— Pour répondre aux questions, pensez à utiliser le code des réponses précédentes.

— À la fin du document, on rappelle quelques méthodes Java pourraient être utiles.

— Quand des consignes manquent de précision (par exemple le type de retour des méthodes), libre à vous de proposer la solution qui vous semble le mieux.

— On supposera que tous les messages circulant sur le réseau sont corrects (on ne vous demande pas de traiter les cas où un message ne respecte pas la spécification).

— Les messages circulant sont signalés entre crochets [...] et les crochets ne font pas partie du message.

— On ne demande pas de traiter les exceptions et on ne demande pas d’écrire les import d’API

Contexte

Nous disposons de serveurs d’images qui acceptent des connexions en TCP pour transmettre des images qu’ils ont. Le but de ce sujet est de programmer un méga-serveur auprès duquel les serveurs d’images s’enregistreront et sur lequel les clients se connecteront pour lui demander de rechercher une image (donnée par son nom) et de la transmettre.

Dans un premier temps, nous expliquerons comment les serveurs d’images fonctionnent ensuite nous verrons comment programmer le méga serveur.

Les serveurs d’images

Un serveur d’images est caractérisé par une adresse IP et par un port de connexion TCP. Nous supposerons que deux serveurs n’ont pas de couple adresse IP-port TCP identique. Pour récupérer une image de nom nom-image sur un serveur d’images, on se connecte au serveur sur le port TCP correspondant et on envoie le message [I nom-image\n], si le serveur n’a pas cette image il répond [N\n] et si en revanche il l’a, il répond en envoyant d’abord le message [O\n] puis en envoyant l’objet de la classe MyImage sérialisé. Le serveur d’images ferme ensuite la connexion.

Le méga-serveur

Les clients de notre application se connectent au méga-serveur qui se connecte lui aux serveurs d’images pour répondre aux requêtes des clients. De plus, les serveurs d’images peuvent s’enregistrer auprès du méga-serveur. Le méga-serveur est caractérisé par un port UDP utilisé par les serveurs d’image pour s’enregistrer et un port TCP utilisé par les clients.

L’idée est la suivante, lorsqu’un client souhaite une image nom-image il envoie un message [R nom-image\n]au méga- serveur qui interroge alors tous les serveurs d’images qui se sont enregistrés auprès de lui jusqu’à trouver l’image. Si il la trouve, il répond au client [V\n] et il lui transmet ensuite l’image sérialisée, et sinon il répond au client [K\n]. Il ferme ensuite la connexion. Pour tester si un serveur d’images a une image il la lui demande comme vu précédemment.

Pour s’enregistrer auprès du méga-serveur, un serveur d’images envoie simplement sur le port UDP du méga-serveur un

message [R port] où port est son numéro d’écoute TCP qui est encodé par une chaîne de 4 caractères correspondant

(2)

au numéro de port (ainsi un serveur d’images est contraint d’avoir un numéro de port TCP compris entre 1000 et 9999). Le méga serveur ne répond rien à ce message, si le serveur d’images n’est pas dans sa liste il l’ajoute et sinon il ne fait rien. De la même façon un serveur d’images peut se désenregistrer en envoyant sur le port UDP du serveur un message [D port] qui a la même forme que le message d’enregistrement. Dans ce cas, si le serveur d’images est présent dans la liste du méga-serveur celui-ci le retire et sinon il ne fait rien. Remarque : Il est normal que l’adresse IP du serveur d’images ne figure pas dans le message car le méga-serveur a la possibilité de la récupérer.

Le but de cet examen est de programmer le méga-serveur ainsi que des clients.

Questions

La première étape consiste à compléter la classe MyImage dont nous donnons le squelette ci-dessous.

/* *

* c l a s s e p e r m e t t a n t de g e r e r des i m a g e s

*/

p u b l i c c l a s s M y I m a g e i m p l e m e n t s S e r i a l i z a b l e { p u b l i c int [ ] [ ] rgb ;

/* *

* c o n s t r u i t une i m a g e a p a r t i r d ’ un f i c h i e r i m a g e ( j p e g / png / bmp / w b m p / gif )

* @ p a r a m p a t h le f i c h i e r i m a g e

* @ t h r o w s I O E x c e p t i o n en cas d ’ e r r e u r d ’ e n t r & e a c u t e ; ee / s o r t i e

*/

p u b l i c M y I m a g e ( S t r i n g p a t h ) t h r o w s I O E x c e p t i o n {

B u f f e r e d I m a g e b u f I m = I m a g e I O . r e a d ( new F i l e ( p a t h ));

rgb = new int [ b u f I m . g e t W i d t h ( ) ] [ b u f I m . g e t H e i g h t ( ) ] ; for ( int i =0; i < b u f I m . g e t W i d t h (); i ++)

for ( int j =0; j < b u f I m . g e t H e i g h t (); j + + ) { rgb [ i ][ j ] = b u f I m . g e t R G B ( i , j );

} }

/* * @ r e t u r n l a r g e u r de l ’ i m a g e */

p u b l i c int g e t W i d t h (){

r e t u r n rgb . l e n g t h ; }

/* * @ r e t u r n h a u t e u r de l ’ i m a g e */

p u b l i c int g e t H e i g h t (){

r e t u r n rgb [ 0 ] . l e n g t h ; }

/* *

* @ r e t u r n une i n s t a n c e de B u f f e r e d I m a g e r e p r e s e n t a n t l ’ i m a g e

*/

p u b l i c B u f f e r e d I m a g e t o B u f f e r e d I m a g e (){

B u f f e r e d I m a g e res = new B u f f e r e d I m a g e ( g e t W i d t h () ,

g e t H e i g h t () , B u f f e r e d I m a g e . T Y P E _ I N T _ R G B );

(3)

for ( int i =0; i < g e t W i d t h (); i ++) for ( int j =0; j < g e t H e i g h t (); j ++)

res . s e t R G B ( i , j , rgb [ i ][ j ]);

r e t u r n res ; }

}

1. Écrire une méthode writeFile de la classe myImage qui prend en argument un nom de fichier et écrit l’image correspondant dans le fichier au format jpeg. Pour cela vous pourrez utiliser la méthode

static boolean write(BufferedImage im, String formatName, File output)throws IOException de la classe ImageIO où formatName vaudra "jpeg".

Nous passons maintenant à la programmation de la classe MegaServer et des classes qu’elle utilisera. Tout d’abord nous programmerons la classe ImageServer qui correspondra à un serveur d’images enregistré dans le méga-serveur.

Le squelette de cette classe est le suivant : p u b l i c c l a s s I m a g e S e r v e r {

/* IP du s e r v e u r d ’ i m a g e s */

p u b l i c S t r i n g Ip ;

/* P o r t TCP du s e r v e u r d ’ i m a g e s */

p u b l i c int p o r t ; }

2. Écrire un constructeur de ImageServer qui prend comme arguments une chaîne de caractères correspondant à une adresse IP et une chaîne de caractères de taille 4 correspondant à un numéro de port et qui remplit les deux champs Ip et port.

3. Écrire une méthode connect de la classe ImageServer qui se connecte au serveur d’images et renvoie la socket correspondante à cette connexion. Cette méthode ne prend pas d’arguments.

4. Écrire une méthode request de la classe ImageServer qui prend en arguments une socket TCP connectée au serveur d’images et un nom d’image nomImage et envoie une requête au serveur d’images pour demander l’image.

5. Écrire une méthode getAnswer de la classe ImageServer qui renvoie un objet de la classe MyImage et prend en arguments une socket TCP connectée au serveur d’images à qui une requête a été envoyée, attend les réponses et si la réponse est [O\n] attend l’image sérialisée et retourne l’objet MyImage correspondant. Dans le cas d’une réponse négative cette méthode renvoie null. (Indication : Vous pourrez d’abord utiliser un BufferedReader pour lire le message et ensuite un ObjectInputStream pour lire l’objet).

6. Écrire une méthode getImage de la classe ImageServer qui prend comme arguments un nom d’images et qui se connecte au serveur d’images, fait une requête d’images et si l’image est envoyée retourne l’objet MyImage correspondant et sinon retourne null.

Nous allons maintenant nous attaquer à la classe MegaServer dont un squelette de code est donné ci-après.

p u b l i c c l a s s M e g a S e r v e r { /* p o r t TCP du M e g a S e r v e r */

p u b l i c int p o r t T C P ;

/* p o r t UDP du M e g a S e r v e r */

p u b l i c int p o r t U D P ;

(4)

/* L i s t e des S e r v e r d ’ i m a g e */

p u b l i c L i n k e d L i s t < I m a g e S e r v e r > l i s t I m a g e S e r v ; }

7. Écrire un constructeur de la classe MegaServer qui prend en arguments deux ports entiers, initialise les champs correspondants et crée la liste listImageServ.

8. Écrire une méthode addImageServ de la classe MegaServer qui prend en arguments une chaîne de caractères correspondant à l’adresse IP d’un serveur d’images et une chaîne de caractères correspondant à son numéro de port et qui ajoute l’objet de la classe ImageServer à la liste (un serveur d’images peut être ajouté plusieurs fois).

9. Écrire une méthode removeImageServ de la classe MegaServ qui prend en arguments une chaîne de caractères correspondant à l’adresse IP d’un serveur d’images et une chaîne de caractères correspondant à son numéro de port et qui retire le serveur d’images correspondant de la liste si il est dedans et sinon ne fait rien (si un serveur d’images est présent plusieurs fois on les retire tous).

La fonction principale de la classe MegaServer va devoir lancer plusieurs types de threads, un pour gérer les messages arrivant sur le port UDP correspondant à l’enregistrement et au désenregistrement des serveurs d’images, l’autre gérant les différentes communications avec les clients. Commençons d’abord par écrire le code de la classe qui gérera les communications UDP. On considère la classe TreatUDP.

p u b l i c c l a s s T r e a t U D P i m p l e m e n t s R u n n a b l e { /* M e g a S e r v e u r a s s o c i e */

M e g a S e r v e r ms ; /* C o n s t r u c t e u r */

p u b l i c T r e a t U D P ( M e g a S e r v e r ms ){

t h i s . ms = ms ; }

}

10. Écrire une méthode treatUDPMess de la classe TreatUDP qui prend en arguments une chaîne de caractères correspondant à un message UDP de la forme [R port] ou [D port] ainsi qu’une chaîne de caractères contenant l’adresse IP du serveur d’images ayant envoyé ce message et qui effectue l’action correspondante au message sur le MegaServer ms.

11. Écrire la méthode run de la classe TreatUDP qui crée une socket UDP pour attendre des messages sur le port UDP du Mega-Serveur ms et traite en boucle chaque message en récupérant l’adresse IP d’où il a été envoyé et en utilisant la fonction treatUDPMess.

Nous allons maintenant passer à la classe TreatTCP responsable des communications TCP.

p u b l i c c l a s s T r e a t T C P i m p l e m e n t s R u n n a b l e { /* M e g a S e r v e u r a s s o c i e */

M e g a S e r v e r ms ;

/* S o c k e t TCP c o r r e s p o n d a n t e au c l i e n t */

S o c k e t so ;

/* C o n s t r u c t e u r */

p u b l i c T r e a t T C P ( M e g a S e r v e r ms , S o c k e t so ){

t h i s . ms = ms ;

(5)

t h i s . so = so ; }

}

12. Écrire une méthode searchImage de la classe TreatTCP qui prend en arguments un nom d’images nomImage et cherche parmi les serveurs de la liste du Mega-Serveur ms si l’un d’eux a l’image et si c’est le cas cette fonction renvoie l’objet MyImage contenant l’image correspondante et sinon la fonction renvoie null (Bien entendu cette fonction devra communiquer avec les serveurs d’image).

13. Écrire la méthode treatTCPMess de la classe treatTCP qui prend en arguments une chaîne de caractères de la forme [I nom-image\n] envoyé par le client et interroge les serveurs d’image à la recherche de nom-image et renvoie soit un objet MyImage correspondant à l’image trouvée, soit null dans le cas contraire.

14. Écrire la méthode run de la classe TreatTCP qui attend sur la socket TCP un message d’un client de la forme [I nom-image\n] et renvoie au client la réponse correspondant à sa requête selon si l’image a été trouvée ou non. Dans le cas où l’image a été trouvée, cette méthode la transmet au client. Cette méthode ferme ensuite la Socket et termine.

Nous retournons programmer la classe MegaServer.

16. Écrire la méthode launch de la classe MegaServer qui lance le thread d’écoute UDP puis attend en boucle des connexions sur son port TCP et pour chaque connexion lance un thread pour gérer la communication.

17. Écrire une méthode principale main qui crée un Mega serveur avec comme port UDP 4444 et comme port TCP 5555 et qui le fait s’exécuter.

18. Écrire dans une classe Client un client qui se connecte au serveur de la machine précédente en supposant que celui-ci s’exécute sur la machine machine.anywhere.fr et lui demande l’image HeartShapedBox et si le serveur l’a, notre client la sauvera dans le fichier myprofile.jpeg.

19. Écrire un client C qui demandera au serveur de la question 18 si les images image1, image2, . . . ,image10 sont disponibles. Bien entendu ce client ne téléchargera pas les images correspondantes car il est écrit en C et ne peut donc pas gérer les images sérialisées, mais il attendra juste la réponse à ses requêtes qui sera de type V ou K.

Quelques fonctions de Java pouvant être utiles

— Méthodes de la classe DatagramPacket I n e t A d d r e s s g e t A d d r e s s ()

// R e t u r n s the a d d r e s s to w h i c h the s o c k e t is c o n n e c t e d .

— Méthodes de la classe InetAddress S t r i n g g e t H o s t A d d r e s s ()

// R e t u r n s the IP a d d r e s s s t r i n g in t e x t u a l p r e s e n t a t i o n .

— Méthodes de la classe LinkedList<E>

b o o l e a n add ( E e )

L i s t I t e r a t o r < E > l i s t I t e r a t o r ()

— Méthodes de la classe ObjectInputStream

(6)

O b j e c t I n p u t S t r e a m ( I n p u t S t r e a m in )

// C r e a t e s an O b j e c t I n p u t S t r e a m t h a t r e a d s f r o m // the s p e c i f i e d I n p u t S t r e a m .

O b j e c t r e a d O b j e c t ()

// R e a d an o b j e c t f r o m the O b j e c t I n p u t S t r e a m .

— Méthodes de la classe ObjectOutputStream

O b j e c t O u t p u t S t r e a m ( O u t p u t S t r e a m out )

// C r e a t e s an O b j e c t O u t p u t S t r e a m t h a t w r i t e s // to the s p e c i f i e d O u t p u t S t r e a m .

v o i d w r i t e O b j e c t ( O b j e c t obj )

// W r i t e the s p e c i f i e d o b j e c t to the O b j e c t O u t p u t S t r e a m . v o i d f l u s h ()

// F l u s h e s the s t r e a m .

— Méthodes de la classe ListIterator<E>

b o o l e a n h a s N e x t () E n e x t ()

v o i d r e m o v e ()

/* R e m o v e s f r o m the l i s t the l a s t e l e m e n t t h a t was r e t u r n e d by n e x t () or p r e v i o u s () ( o p t i o n a l o p e r a t i o n ). T h i s c a l l can o n l y be m a d e o n c e

per c a l l to n e x t or p r e v i o u s . It can be ma d e o n l y if add ( E ) has not b e e n c a l l e d a f t e r the l a s t c a l l to n e x t or p r e v i o u s . */

— Méthodes de la classe String int l e n g t h ()

S t r i n g s u b s t r i n g ( int b e g i n I n d e x , int e n d I n d e x )

// R e t u r n s a new s t r i n g t ha t is a s u b s t r i n g of t h i s s t r i n g . // The s u b s t r i n g b e g i n s at the s p e c i f i e d b e g i n I n d e x

// and e x t e n d s to the c h a r a c t e r at i n d e x e n d I n d e x - 1.

// T h u s the l e n g t h of the s u b s t r i n g is e n d I n d e x - b e g i n I n d e x . // The f i r s t i n d e x is 0.

— Méthodes de la classe Integer

s t a t i c int p a r s e I n t ( S t i n g s )

/* P a r s e s the s t r i n g a r g u m e n t as a s i g n e d d e c i m a l i n t e g e r */

Références

Documents relatifs

Il faudra seulement rajouter une route vers le

On considére un groupe de 3 étudiants participant à 5 disciplines différentes. Ecrire un programme 

- Ecrire une fonction récursive qui calcule le PGCD de deux entiers positifs. On suppose qu’on ne peut effectuer que

Une pile est représentée par une structure regroupant un entier, pour le sommet, et un tableau de MAX_PILE éléments (ici, des caractères). II.1- En utilisant la

Ce n'est pas une bonne pratique d'un point de vue sécurité car cela veut dire que les machines de l'entreprise peut communiquer directement entre elles.. Si l'une d'elle est

Dans la liste des périodes possibles, on trouve avec une période telle que abcde les périodes bcdea, cdeab, deabc, eabcd ; d’où 10 périodes multiples de 2439, compatibles avec 41

Ainsi, lorsqu'un utilisateur se connecte à internet à l'aide d'une application cliente configurée pour utiliser un serveur proxy, celle-ci va se connecter en premier lieu au

Pour déterminer l’image d’un réel par une fonction , on prend ce réel sur l’axe des abscisses , on rejoint la courbe et on lit l’ordonnée de ce point.. Ne pas oublier de