Université Kasdi Merbah Ouargla Département Mathématique et informatique 1éme année Master informatique Module ADIS &SAD TP N°1 Avril 2012 1. L’architecture Java RMI Les amorces (Stub et Skeleton) : programmes jouant le rôle d’adaptateurs pour le transport des appels distants (Skeleton n’est pas nécessaire pour Java SDK). Ces amorces sont générées par le compilateur des amorces : rmic La couche des références d’objets distants : permet d’obtenir la référence d’un objet distant à partir de la référence locale Stub. Page: 1 S.Euschi C’est un service d’annuaire pour les objets distants enregistrés sur le serveur. Lancée par le programme rmiregistry. La couche de transport : connecte les deux amorces (une souche de la JVM client et une souche de la JVM serveur) en utilisant TCP/IP. 2. Un exemple : l’écho distant L’application serveur (interEcho.java et srvEcho.java) Étape 1 : l’interface de l’objet sur le serveur (interEcho.java) import java.rmi.*; // l'interface distante public interface interEcho extends Remote{ public String echo(String msg) throws java.rmi.RemoteException; } On déclare une interface interEcho déclarant une méthode echo comme accessible à distance. Le traitement de l’exception utilise la classe RemoteException de java.rmi. Étape 2 : écriture de l’objet serveur (srvEcho.java) import java.rmi.*; import java.rmi.server.*; import java.net.*; // classe implémentant l’écho distant public class srvEcho extends UnicastRemoteObject implements interEcho{ // constructeur public srvEcho() throws RemoteException{ super(); }// fin constructeur // méthode réalisant l’écho public String echo(String msg) throws RemoteException{ return "[" + msg + "]"; }// fin écho // création du service public static void main (String arg[]){ try{ srvEcho serveurEcho=new srvEcho(); Naming.rebind("srvEcho",serveurEcho); System.out.println("Serveur d’écho prêt"); } catch (Exception e){ System.err.println(" Erreur " + e + " lors du lancement du serveur d’écho "); } }// main }// fin classe Page: 2 S.Euschi Nous devons créer un objet de type srvEcho et l’enregistrer dans l’annuaire des objets accessibles de l’extérieur. Cet enregistrement se fait avec la méthode rebind de la classe Naming : Naming.rebind(String nom, Remote obj) avec nom le nom qui sera associé à l’objet distant obj l’objet distant Dans l’exemple : Naming.rebind("srvEcho",serveurEcho); La classe srvEcho est dérivée de la classe UnicastRemoteObject, l’objet créé s’exécute indéfiniment : il écoute les demandes des clients sur un port anonyme c’est à dire choisi par le système selon les circonstances. Étape 3 : compilation de l’application serveur Javac interEcho.java, srvEcho.java L’application client Étape 4 : écriture du client (cltEcho.java) On écrit un client à qui on passe en paramètre l’URL du serveur d’écho et qui 1. lit une ligne tapée au clavier 2. l’envoie au serveur d’écho 3. affiche la réponse que celui-ci envoie 4. reboucle en 1 et s’arrête lorsque la ligne tapée est « fin ». import java.rmi.*; import java.io.*; public class cltEcho { public static void main(String arg[]){ // syntaxe : cltEcho URLService // vérification des arguments if(arg.length!=1){ System.err.println("Syntaxe : pg url_service_rmi"); System.exit(1); } // dialogue client-serveur String urlService=arg[0]; BufferedReader in=null; String msg=null; String reponse=null; interEcho serveur=null; try{ // ouverture du flux clavier in=new BufferedReader(new InputStreamReader(System.in)); // localisation du service serveur=(interEcho) Naming.lookup(urlService); // boucle de lecture des msg à envoyer au serveur d'écho System.out.print("Message : "); msg=in.readLine().toLowerCase().trim(); while(! msg.equals("fin")){ // envoi du msg au serveur et réception de la réponse reponse=serveur.echo(msg); // suivi System.out.println("Réponse serveur : " + reponse); // msg suivant System.out.print("Message : "); Page: 3 S.Euschi msg=in.readLine().toLowerCase().trim(); }// while // c'est fini System.exit(0); // gestion des erreurs } catch (Exception e){ import java.rmi.*; import java.io.*; public class cltEcho { public static void main(String arg[]){ // syntaxe : cltEcho URLService // vérification des arguments if(arg.length!=1){ System.err.println("Syntaxe : pg url_service_rmi"); System.exit(1); } // dialogue client-serveur String urlService=arg[0]; BufferedReader in=null; String msg=null; String reponse=null; interEcho serveur=null; try{ // ouverture du flux clavier in=new BufferedReader(new InputStreamReader(System.in)); // localisation du service serveur=(interEcho) Naming.lookup(urlService); // boucle de lecture des msg à envoyer au serveur d'écho System.out.print("Message : "); msg=in.readLine().toLowerCase().trim(); while(! msg.equals("fin")){ // envoi du msg au serveur et réception de la réponse reponse=serveur.echo(msg); // suivi System.out.println("Réponse serveur : " + reponse); // msg suivant System.out.print("Message : "); msg=in.readLine().toLowerCase().trim(); }// while // c'est fini System.exit(0); // gestion des erreurs } catch (Exception e){ System.err.println("Erreur : " + e); System.exit(2); }// try }// main }// classe L’instruction qui demande une référence de l’OD sur le serveur : serveur=(interEcho) Naming.lookup(urlService); La méthode lookup utilisée admet comme paramètre l’url du service demandé. Celle-ci a la forme d’une url classique : rmi://machine:port/nom_service avec rmi : facultatif - protocole rmi machine : nom ou adresse IP de la machine sur laquelle opère le serveur d’écho facultatif, par défaut localhost. Port : port d’écoute du service d’annuaire de cette machine - facultatif, par défaut 1099 nom_service nom sous lequel a été enregistré le service demandé (srvEcho pour notre exemple) Le client aura une instance de l’interface distante interEcho. Si on suppose que le client et le serveur ne sont pas sur la même machine, lorsqu’on compile le client cltEcho.java, on doit disposer dans le même répertoire, du fichier interEcho.class, résultat de la compilation de l’interface distante interEcho, sinon on aura une erreur de compilation sur les lignes qui référencent cette interface. Page: 4 S.Euschi interEcho..java (idem à celui du serveur) import java.rmi.*; // l'interface distante public interface interEcho extends Remote{ public String echo(String msg) throws java.rmi.RemoteException; } Étape 5 : génération des fichiers .class nécessaires à l’application client Javac interEcho.java, cltEcho.java Etape 6 : génération des amorces client et serveur Au niveau du serveur et à partir de la classe srvEchi.class on va produire les classes : srvEcho_Stub.class et srvEcho_Skel.class avec le compilateur rmic de java rmic –vcompat srvEcho On fait une copie du fichier srvEcho_stub.class dans le répertoire du client. Étape 7: Exécution de l’application client-serveur d’écho Sur le serveur on lance : rmiregistry & (lancé en tache de fond dans une fenêtre DOS) ou start rmiregistry (préférable) Dans une fenetre Dos on lance : java srvEcho ou start java srvEcho (préférable) Le serveur nous répond par : Serveur d’écho prêt Il ne nous reste plus qu’à lancer et tester notre client : java cltEcho rmi://localhost/srvEcho Le client distant utilise le service distant implémenté sur le serveur (une instance de l’objet srvEcho qui implémente la méthode srvEcho.echo()) en envoyant des messages et le serveur réalise l’echo de chaque message tant que le message envoyé par le client est différent de « fin ». Page: 5 S.Euschi Exécution de l’exemple : D:\exemple\serveur>start rmiregistry D:\exemple\serveur>start java srvEcho D:\exemple\client>java cltEcho rmi://localhost/srvEcho Résultats : Message : Bonjours Réponse serveur : [Bonjours] . . . Message : fin Page: 6 S.Euschi