next up previous contents index
Next: 41 Introduction à JDBC Up: Java: Programmation avancée Previous: 39 Programmation réseau

Subsections

40 Appel de méthodes distantes (RMI)

40.1 Introduction

Les systèmes distribuées sont des applications sur des espaces d'adressage différents: ou sur un même hôte ou des hôtes différents. Le problème central de ce type d'applications est la communication entre les différentes applications.

Pour le moment, nous nous sommes contenté de tranférer des données à travers le réseau. Nous l'avons fait les divers protocoles existants: FTP, HTTP, etc. Nous avons vu, qu'avec les sockets, il existe un moyen simple de communication en une application serveur et une application cliente pour transférer des données. Jusqu'à présent, nous ne connaisons que les CGI qui permettent de lancer un programme sur une machine distante.

Les appels de procédures distantes (RPC: Remote Procedure Call ) est un autre moyen pour exécuter des programmes distants. Le but du service RPC est de permettre la programmation aisée de programmes client-serveur sous une forme transparente aux utilisateurs.

L'idée de base est que le paradigme d'appel de procédure est bien connu des programmeurs. Le RPC va permettre de distribuer (ou répartie) le programme principal et les procédures sur des systèmes distants :

Ainsi, au lieu de manipuler directement des sockets, avec le RPC, le programmeur va avoir l'illusion de faire des appels à des procédures locales alors même que ces appels impliquent une communication avec un hôte distant pour envoyer et recevoir des données.

La difficulté essentielle à résoudre pour offrir un service d'appel de procédures à distance est le maintien des propriétés implicitement associées à un appel de procédure local :

40.2.2 Le client

Le RPC maintient une certaine transparence : du point de vue du client, la procédure appelée apparaît comme une procédure locale. En fait, la procédure distante appelée est représentée localement par une procédure particulière appelée stub client ou souche cliente : c'est cette procédure locale que le client invoque réellement. Cette souche cliente utilise ensuite le réseau pour contacter la procédure distante implantée par le serveur. Le rôle de la souche cliente est multiple :

40.2.1 Le serveur

Au niveau du serveur, on définit la notion de programme serveur : il est identifié par un numéro de programme non ambigu, un numéro de version qui permet éventuellement la coexistence de versions successives du même programme serveur, et il est constitué d'un ensemble de procédures. Un module particulier contrôle l'accès aux procédures du serveur, le "stub serveur".

Communication stub client/Serveur

La communication entre le stub client et le stub serveur se fait indirectement via deux services :

Les échanges à travers le réseau peuvent se faire soit via TCP, soit via UDP

RPC et RMI

RPC a été conçu pour la programmation procédurale et ne prévoit rien en ce qui concerne la programmation objet. L'adaptation de RPC à la programmation objet a pour nom RMI (Remote Method Invocation ). S'il existe des RMI qui peuvent s'adapter aux objets Java , le langage Java fournit un RMI qui est propre aux objets Java . Il s'agit ici de travailler dans un monde homogène Java ; contrairement à CORBA qui présuppose une environnement hétérogène, des langages différents.

Java Remote Invocation Method

On appelle objets distants tout objet dont les méthodes sont susceptibles d'être invoquées par une machine virtuelle Java autre que celle sur laquelle réside cet objet. Il s'agit généralement d'une machine distante.

Lors de l'invocation d'une méthode distante, il reste un problème délicat posé par le passage de ses arguments et l'objet éventuellement retourné par celle-ci.

 

A TERMINER

L'ensemble des classes qui prennent en charge la gestion des RMI sont regroupées dans les packages java.rmi, java.rmi.server, java.rmi.registry et java.rmi.dgc.

Package java.rmi package pour la gestion client
Package java.rmi.server package pour la gestion du serveur
Package java.rmi.registry package pour localiser les objets distants
Package java.rmi.dgc récupération de mémoire

43.1 Un exemple

Avant d'entrer dans les détails, voici l'exemple fournit dans le tutorial de jdk.

Le serveur

L'interface java.rmi.Remote

Un objet distant se doit d'implanter une ou plusieurs interfaces distantes ; une interface distante est une interface qui étend directement ou indirectement l'interface java.rmi.Remote.

L'interface java.rmi.Remote ne définit aucune méthode propre, c'est une interface vide qui ne sert qu'à identifer les objets suscpetibles d'être des objets distants.

L'ensemble des exceptions que l'invocation d'une méthode distante peut générée est regroupé dans la classe java.rmi.RemoteException et toutes les méthodes implantant cette interface se doivent de renvoyer cette exception.

 
public interface Hello extends java.rmi.Remote {
        String sayHello() throws java.rmi.RemoteException;
}

L'implantation de l'interface

A présent, nous allons définir une classe qui implante cette interface ce qui va nous permettre de définir (plus tard) des objets distants qui seront des instances de cette classe. Cette classe doit être une sous classe de la classe java.rmi.server.UnicastRemoteObject.

 
public class HelloImpl extends java.rmi.server.UnicastRemoteObject implements Hello {
Sans plus de détails, disons que cette classe java.rmi.server.UnicastRemoteObject fournit un ensemble de méthodes qui vont permettre l'invocation des méthodes distantes.

Il nous faut, maintenant, implanter la méthod sayHello de l'interface Hello définit précédemment.

 
public String sayHello() throws java.rmi.RemoteException { return  "Coucou !"; }
C'est la seule méthode (d'après notre interface) qui peut être invoqué par le client. Elle se contente de retourner au client la chaîne de caractères "Coucou !". A priori, rien ne distingue cette méthode des autres méthodes que l'on pourrait fournir avec cette classe. Seule son appartenance à l'interface Hello lui confère un statut particulier.

Il nous reste à terminer l'implantation de la classe en fournissant la méthode main, et le constructeur de notre classe.

Le constructeur de cette classe ne fait rien d'autre que d'appeler le constructeur de la classe mère; ce qui est le comportement par défaut si l'on ne définit aucun constructeur. Pourtant, ici, il va falloir impérativement, la définir à cause de l'exception qu'elle peut engendrer.

 
public HelloImpl() throws RemoteException { super(); }
La méthode main se charge des opérations à effectuer sur le serveur. On crée tout d'objet une instance de cette classe que l'on enregistre le registre de nommage avec la méthode statique rebind de la classe java.rmi.Naming.
 
HelloImpl obj = new HelloImpl("Hello");
java.rmi.Naming.rebind("Hello", obj);
System.out.println("Le serveur RMI Hello est actif");
\end{alltt}\end{formatprog}

C'est cet enregistrement qui met à la disposition du client ces objets. 
Les clients peuvent alors accès à cet objet ou à la liste des objets disponibles.


Voici le code complet de cette classe.

\begin{formatprog}
\verbatimfile{Programme/rmi/HelloImpl.java}
\end{formatprog}





\formatsection\subsubsection{Fabriquer les stubs et squelettes}\formattext



La partie du codage en \Java\ de notre serveur est à présent fini. IL nous reste à fabriquer les \emph{stubs} et \texttt{squelettes} indispensable aux appels distants.



L'utilitaire \texttt{rmic} prend la fichier \texttt{.class} et produit
ces \emph{stubs} et \emph{squelettes}:

\begin{formatprog}\begin{alltt}
\emph{% javac HelloImpl.java}
\emph{% rmic HelloImpl}
\end{alltt}\end{formatprog}

Cette dernière commande produit les deux fichiers \texttt{HelloImpl\_Skel.class}
 et \texttt{HelloImpl\_Stub.class}





\formatsection\subsubsection{Mise en route du serveur}\formattext

A présent, tout est prêt pour la mise en route du serveur. Avant toute chose, il faut lancer le programme \texttt{rmiregistry}
\begin{formatprog}\begin{alltt}
\emph{% rmigestry 2000  &     \emph{// sous unix}}
\emph{% start rmirestry 2000 \emph{// sous Windows}}
\end{alltt}\end{formatprog}

Ce programme s'exécute en tâche de fond et se connect par défaut au port 1099.
Si ce port est pris, il suffit de spécifier le port que l'on veut utiliser.
Ce numéro de port est celui utilisé par le programme \texttt{HelloImpl}:

\begin{formatprog}\begin{verbatim}
         java.rmi.Naming.rebind("//gbm.esil.univ-mrs.fr:2048", obj);
Le lancement du serveur proprement dit se fait en excéutant la programme HelloImpl:
 
% java HelloImpl & 
Le serveur RMI Hello est actif
% 
A présent tout est prêt pour recevoir des appels distants !!!

Le client

Le client doit définir l'objet distant dont il veut obtenir une référence. Comment un client peut-il désigné un objet distant ? La syntaxe utilisé est propre de la syntaxe des URL HTTP. Le protocole utilisé est rmi, l'objet réside sur la machine gbm.esil.univ-mrs.fr et le serveur est à l'écoute sur le port 2048 et l'objet recherché s'est fait inscrire sous le nom de Hello. Le client désigne alors cet objet par :

 
rmi://gbm.esil.univ-mrs.fr/Hello
La classe Naming dispose d'une méthode statique lookup qui permet de récupérer cet objet :
 
Objet o = Naming.lookup("rmi://gbm.esil.univ-mrs.fr:2048/Hello");
Une fois extrait cet objet, il suffit d'invoquer la méthode sayHello sur cet objet.
 
Objet o = Naming.lookup("rmi://gbm.esil.univ-mrs.fr/Hello");

 
\verbatimfile{Programmes/rmi/CallHello.java}

40.2.3 La compilation

 
javac Hello.java HelloImpl.java

 
rmic HelloImpl

40.2.4 L'exécution

 
start rmiregistry  2048     // Windows
rmiregistry  2048 &         //  Unix

 
java HelloImpl &

 
java CallHello


next up previous contents index
Next: 41 Introduction à JDBC Up: Java: Programmation avancée Previous: 39 Programmation réseau
Touraivane
6/12/1998