Rappel des conclusions sur l’appel de procédure à distance

Ce document présente les concepts fondamentaux et les techniques liés à l'appel de procédure à distance (RPC) étendu aux objets, en particulier à travers l'exemple de Java RMI (Remote Method Invocation).

D'après le document Rappel des conclusions sur l’appel de procédure à distance

Cet article a été rédigé automatiquement à partir du document source, puis vérifié avant publication.

Document source

Rappel des conclusions sur l’appel de procédure à distance

Java RMI, Distributed Computing, Object-Oriented Programming · PDF · 13 pages

Afficher l'aperçu du document

Consulter le document original →

Ce document présente les concepts fondamentaux et les techniques liés à l'appel de procédure à distance (RPC) étendu aux objets, en particulier à travers l'exemple de Java RMI (Remote Method Invocation). Il s'adresse aux étudiants et développeurs souhaitant comprendre la construction d'applications réparties basées sur des objets distants, leurs avantages, limitations, et leur mise en œuvre pratique.

Avantages et limitations de l’appel de procédure à distance

L’appel de procédure à distance permet d’abstraire les détails de la communication entre machines, facilitant ainsi le développement d’applications réparties. Des outils de génération automatisée simplifient la mise en œuvre, et l’intégration dans un langage de programmation facilite la portabilité et la mise au point des applications.

Toutefois, cette approche présente des limites :

  • La structure de l’application est statique : il n’y a pas de création dynamique de serveur ni de redéploiement entre sites.
  • Le passage des paramètres par référence n’est pas possible, la communication est limitée à un schéma synchrone.
  • La persistance des données n’est pas assurée automatiquement, elle doit être réalisée explicitement par sauvegarde dans des fichiers.

Des mécanismes plus évolués, tels que les objets répartis (Java RMI, CORBA), les bus à messages (Message Oriented Middleware) ou les composants répartis (EJB, Corba CCM, .Net), visent à remédier à ces limitations.

Intérêt des objets pour la construction d’applications réparties

  • Encapsulation : l’interface (méthodes et arguments) est la seule voie d’accès à l’état interne de l’objet, qui reste inaccessible directement.
  • Classes et instances : mécanismes de génération d’exemplaires conformes à un même modèle.
  • Héritage : facilite la spécialisation, la récupération et la réutilisation du code existant.
  • Polymorphisme : permet différentes mises en œuvre des fonctions d’une interface, facilitant l’évolution et l’adaptation des applications.

Extension du RPC aux objets

L’appel de procédure est étendu à l’appel de méthode sur un objet distant. Par exemple, insérer une entrée dans un annuaire distant se fait par appel d’une méthode sur un objet distant.

Avant d’appeler une méthode distante, il faut créer des instances d’une classe d’objets sur le serveur. Cette création est souvent réalisée via une fabrique (factory) qui permet de construire ces instances localement sur le serveur.

Notion de référence d’objet

Une référence d’objet distant contient toutes les informations nécessaires pour atteindre l’objet :

  • Localisation (adresse IP du site de résidence)
  • Numéro de port sur le site
  • Localisation interne au serveur

Cette référence est opaque et ne peut être utilisée que via un mécanisme d’appel à distance. Par exemple :

  • En Java RMI, la référence est appelée stub (talon client).
  • En CORBA, la référence est spécifiée par l’IOR (Interoperable Object Reference).
  • En DCOM, le format est propriétaire.

Java RMI (Remote Method Invocation)

Principes et règles d’usage

Java RMI permet la construction d’applications réparties en Java, en appelant des méthodes sur des objets distants selon un schéma similaire au RPC. Le programmeur fournit :

  • Une ou plusieurs interfaces décrivant les méthodes accessibles à distance (IDL = Java, pas d’IDL séparé).
  • Le programme serveur, contenant les objets implémentant ces interfaces et le serveur d’objets.
  • Le programme client, qui invoque les méthodes distantes.

L’environnement Java fournit un générateur de talons (rmic) et un service de noms (Object Registry).

Interface distante

  • L’interface distante doit être publique et étendre java.rmi.Remote.
  • Chaque méthode doit déclarer l’exception java.rmi.RemoteException.
  • Les objets locaux passés en paramètre sont transmis par valeur et doivent être sérialisables (implémenter java.io.Serializable).
  • Les objets distants sont passés par référence, désignés par leur interface.

Implémentation d’un objet distant

Une classe distante doit :

  • Implémenter une interface distante (Remote).
  • Étendre java.rmi.server.UnicastRemoteObject (ou autre mécanisme d’export).
  • Fournir l’implémentation des méthodes accessibles à distance.
import java.rmi.*;
import java.rmi.server.*;

public class Reverse extends UnicastRemoteObject implements ReverseInterface {
    public Reverse() throws RemoteException {
        super();
    }

    public String reverseString(String ChaineOrigine) throws RemoteException {
        int longueur = ChaineOrigine.length();
        StringBuffer temp = new StringBuffer(longueur);
        for (int i = longueur; i > 0; i--) {
            temp.append(ChaineOrigine.substring(i - 1, i));
        }
        return temp.toString();
    }
}

Serveur d’objets

Le serveur réalise les opérations suivantes :

  1. Définir un gestionnaire de sécurité (RMISecurityManager) pour autoriser le chargement de classes sérialisables.
  2. Créer les objets distants par instanciation.
  3. Exposer les objets distants (automatiquement si la classe étend UnicastRemoteObject, sinon via exportObject).
  4. Enregistrer les objets dans le serveur de noms (rmiregistry) avec Naming.rebind.
import java.rmi.*;

public class ReverseServer {
    public static void main(String[] args) {
        System.setSecurityManager(new RMISecurityManager());
        try {
            System.out.println("Serveur : Construction de l’implémentation");
            Reverse rev = new Reverse();
            System.out.println("Objet Reverse lié dans le RMIregistry");
            Naming.rebind("rmi://localhost:1099/MyReverse", rev);
            System.out.println("Attente des invocations des clients ...");
        } catch (Exception e) {
            System.out.println("Erreur de liaison de l’objet Reverse");
            System.out.println(e.toString());
        }
    }
}

Client RMI

Le client récupère le stub de l’objet distant via le serveur de noms en invoquant Naming.lookup avec une URL de la forme :

rmi://machine:port/nom

Si le nom de machine ou le port sont omis, la machine locale et le port 1099 par défaut sont utilisés.

Exemple d’appel de récupération et d’utilisation du stub :

import java.rmi.*;

public class ReverseClient {
    public static void main(String[] args) {
        System.setSecurityManager(new RMISecurityManager());
        try {
            ReverseInterface rev = (ReverseInterface) Naming.lookup("rmi://localhost:1099/MyReverse");
            String result = rev.reverseString(args[0]);
            System.out.println("L’inverse de " + args[0] + " est " + result);
        } catch (Exception e) {
            System.out.println("Erreur d’accès à l’objet distant.");
            System.out.println(e.toString());
        }
    }
}

Gestionnaire de sécurité

Le gestionnaire de sécurité protège la machine virtuelle Java contre l’exécution de code malicieux. Il est installé avec :

System.setSecurityManager(new RMISecurityManager());

La politique de sécurité (fichier java.policy) spécifie les permissions, notamment sur les sockets (connect, accept, listen).

Exemple de fichier java.policy :

grant {
    permission java.net.SocketPermission "localhost 1024-65535", "connect,accept";
    permission java.net.SocketPermission ":80", "connect";
};

Fabrique d’objets (Factory)

La fabrique permet au client de créer plusieurs instances d’une classe distante sur le serveur, car le mot-clé new ne fonctionne que localement.

Le client appelle un objet fabrique qui crée localement les instances sur le serveur.

/* Interface de l’objet distant */
public interface Annuaire extends Remote {
    public boolean inserer(String nom, int id) throws RemoteException;
    public boolean supprimer(String nom, int id) throws RemoteException;
    public Info rechercher(String nom) throws RemoteException;
}

/* Interface de fabrique d’objets */
public interface FabAnnuaire extends Remote {
    public Annuaire newAnnuaire(String titre) throws RemoteException;
}

/* Implémentation de l’objet distant */
public class AnnuaireImpl extends UnicastRemoteObject implements Annuaire {
    private String titre;
    public AnnuaireImpl(String titre) { this.titre = titre; }
    public boolean inserer(String nom, Info info) throws RemoteException { /* ... */ }
    public boolean supprimer(String nom) throws RemoteException { /* ... */ }
    public Info rechercher(String nom) throws RemoteException { /* ... */ }
}

/* Implémentation de la fabrique */
public class FabAnnuaireImpl extends UnicastRemoteObject implements FabAnnuaire {
    public FabAnnuaireImpl() { }
    public Annuaire newAnnuaire(String titre) throws RemoteException {
        return new AnnuaireImpl(titre);
    }
}

Serveur d’objets avec fabrique

import java.rmi.*;

public class Server {
    public static void main(String[] argv) {
        System.setSecurityManager(new RMISecurityManager());
        try {
            Naming.rebind("Fabrique", new FabAnnuaireImpl());
            System.out.println("Serveur prêt.");
        } catch (Exception e) {
            System.out.println("Erreur serveur : " + e);
        }
    }
}

Code client utilisant la fabrique

import java.rmi.*;

public class HelloClient {
    public static void main(String[] argv) {
        System.setSecurityManager(new RMISecurityManager());
        try {
            FabAnnuaire fabrique = (FabAnnuaire) Naming.lookup("rmi://goedel.imag.fr/Fabrique");
            Annuaire annuaireIMAG = fabrique.newAnnuaire("IMAG");
            Annuaire annuaireINRIA = fabrique.newAnnuaire("INRIA");
            annuaireIMAG.inserer(..., ...);
            annuaireINRIA.inserer(..., ...);
        } catch (Exception e) {
            System.out.println("Erreur client : " + e);
        }
    }
}

Passage d’objets en paramètres

Deux cas se présentent :

  • Objet local : passage par valeur, une copie de l’objet est transmise. L’objet doit être sérialisable (implémenter java.io.Serializable). Exemple : un objet Info transmis au serveur.
  • Objet distant : passage par référence, une référence (stub) est transmise. Exemple : un objet Annuaire passé en paramètre.

Objets sérialisables

  • Un objet sérialisable doit implémenter java.io.Serializable.
  • Les objets référencés dans cet objet doivent aussi être sérialisables.
  • Les variables primitives ne nécessitent pas d’action particulière.
  • Une variable peut être exclue de la sérialisation en la déclarant transient.
  • Pour des champs non sérialisables, il faut fournir les méthodes readObject() et writeObject().

Fonctionnement interne de Java RMI

Une classe distante étend UnicastRemoteObject. Lors de la création d’une instance :

  • Le constructeur de UnicastRemoteObject crée une instance de stub (générée par rmic) qui contient une variable ref de type RemoteRef avec la localisation de l’objet (adresse IP, port).
  • Les appels de méthode se font par ref.invoke(), utilisant des sockets pour la communication.

Serveur de noms (registry)

  • La classe Naming permet d’enregistrer, rechercher et supprimer des objets distants via les méthodes bind(), rebind(), lookup(), unbind(), list().
  • LocateRegistry permet de localiser ou créer un serveur de noms (rmiregistry).

Appel en retour (callback)

Le callback permet au serveur d’appeler le client, augmentant ainsi l’asynchronisme et le dynamisme :

  • Le client passe un objet au serveur.
  • Le serveur effectue un appel asynchrone sur cet objet.

Ce mécanisme permet au serveur de demander des informations complémentaires au client ou d’utiliser des services fournis par celui-ci, par exemple pour le traitement d’exceptions.

Conclusion

  • L’extension du RPC aux objets permet l’accès à des objets distants sans langage séparé de description d’interfaces (IDL intégré à Java).
  • Les limitations principales sont l’environnement restreint à Java, un service de noms élémentaire, et l’absence de services additionnels comme la duplication d’objets ou les transactions.
  • Des passerelles existent, notamment RMI/IIOP, pour interopérer avec d’autres environnements.

Perspectives

  • Parallélisme sur le serveur : un serveur RMI peut servir plusieurs clients simultanément via des threads. La synchronisation doit être assurée par le développeur.
  • Activation automatique : un démon spécialisé (rmid) peut lancer automatiquement plusieurs classes serveur sur un site distant.
  • Téléchargement de code : un chargeur spécial (ClassLoader) peut être développé pour télécharger les classes nécessaires à l’exécution.

Glossaire des termes clés

  • Appel de procédure à distance (RPC) : mécanisme permettant d’exécuter une procédure sur une machine distante.
  • Objet distant : objet accessible via un réseau, dont les méthodes peuvent être invoquées à distance.
  • Stub (talon client) : représentant local d’un objet distant, qui gère la communication avec le serveur.
  • Skeleton (talon serveur) : composant côté serveur qui reçoit les appels, désassemble les paramètres et invoque la méthode distante.
  • UnicastRemoteObject : classe Java qui facilite la création d’objets distants accessibles via RMI.
  • RMISecurityManager : gestionnaire de sécurité protégeant la JVM lors des appels distants.
  • Fabrique (Factory) : objet distant chargé de créer des instances d’autres objets distants sur le serveur.
  • Sérialisation : mécanisme de transformation d’un objet en un flux de données pour transmission ou stockage.
  • RemoteException : exception levée lors d’erreurs dans les appels distants.
  • Registry (serveur de noms) : service permettant d’enregistrer et de retrouver des objets distants par nom.
  • Callback (appel en retour) : mécanisme où le serveur appelle un objet passé par le client pour notifier ou interagir.

Points clés à retenir

  • L’appel de procédure à distance étendu aux objets facilite la construction d’applications réparties en Java.
  • Java RMI repose sur des interfaces distantes, des stubs, skeletons, et un serveur de noms.
  • Les objets distants doivent étendre UnicastRemoteObject et implémenter une interface distante.
  • Le passage des objets en paramètres peut se faire par valeur (objets locaux sérialisables) ou par référence (objets distants).
  • Le gestionnaire de sécurité est essentiel pour protéger la JVM lors des appels distants.
  • La fabrique d’objets permet la création dynamique d’instances sur le serveur.
  • Le client récupère les références d’objets distants via le serveur de noms et invoque leurs méthodes comme s’il s’agissait d’objets locaux.
  • Le callback permet d’augmenter l’asynchronisme et le dynamisme des interactions client-serveur.

Partager

Commentaires

Aucun commentaire pour le moment. Posez la première question.

Les commentaires sont relus avant publication. Votre e-mail n'est jamais affiché.

← Toutes les révisions