Systèmes et Applications Répartis
Exercice 1 : Questions diverses Question 1 - Comparaison entre RPC et RMI Voici le tableau comparatif complété des mécanismes de communication RPC (Remote Procedure Call) et RMI (Remote Method Invocation). Caractéristique RPC RMI Plateforme (1/multi) Multi-plateformes Multi-plateformes (via la JVM) Langage de programmation C, C++, etc.
D'après le document Systèmes et Applications Répartis
Cet article a été rédigé automatiquement à partir du document source, puis vérifié avant publication.

Document source
Programming, Distributed Systems · PDF · 10 pages · 2013
Afficher l'aperçu du document
Exercice 1 : Questions diverses
Question 1 - Comparaison entre RPC et RMI
Voici le tableau comparatif complété des mécanismes de communication RPC (Remote Procedure Call) et RMI (Remote Method Invocation).
| Caractéristique | RPC | RMI |
|---|---|---|
| Plateforme (1/multi) | Multi-plateformes | Multi-plateformes (via la JVM) |
| Langage de programmation | C, C++, etc. (multi-langages) | Java (spécifique à Java) |
| Utilitaire d'IDL | rpcgen |
javac (et historiquement rmic) |
| Protocole réseau | TCP/IP, UDP | TCP/IP, HTTP, IIOP |
| Serveur de nommage | portmapper (ou rpcbind) |
rmiregistry |
| Extra | Base du système de fichiers NFS | Permet le chargement dynamique de classes |
Question 2 - Commande de vérification des services RPC
La commande Unix qui permet de lister les services RPC disponibles sur un serveur est :
rpcinfo -p
Exemples communs de services RPC :
portmap(ourpcbind) : le service de mappage des ports lui-même.nfs(Network File System) : pour le partage de fichiers en réseau.mountd: le démon de montage pour NFS.
Question 3 - Explication des commandes système
a) rpcinfo –u localhost 53667767
Cette commande effectue un appel (une sorte de "ping" applicatif) à la procédure 0 du programme RPC portant le numéro d'identification 53667767 sur la machine locale (localhost), en utilisant le protocole UDP (indiqué par le drapeau -u). Cela permet de vérifier si ce service spécifique est enregistré et répond correctement sur le réseau.
b) Commande d'exécution Java RMI
java -Djava.security.policy=../tous.policy \
-Djava.rmi.server.codebase=http://machine.ensi.rnu.tn/ \
chat.server.RemoteServerImpl MonNomServer
Cette commande lance la classe serveur chat.server.RemoteServerImpl (qui prend ici l'argument MonNomServer) au sein de la Machine Virtuelle Java. Les drapeaux -D définissent des propriétés système vitales pour RMI :
java.security.policy=../tous.policy: Spécifie le fichier de politique de sécurité à utiliser, obligatoire pour autoriser le téléchargement dynamique de code en RMI.java.rmi.server.codebase=[http://machine.ensi.rnu.tn/](http://machine.ensi.rnu.tn/): Indique l'URL à partir de laquelle les clients pourront télécharger les classes (les stubs) nécessaires pour interagir avec ce serveur.
Question 4 - Obtention d'une référence à l'objet distant
La bonne ligne de code est la réponse e) :
RobjInt q = (RobjInt)Naming.lookup(...);
Explication : La méthode Naming.lookup() retourne un objet de type générique java.rmi.Remote. En RMI, le client manipule toujours l'interface distante (RobjInt), et non l'implémentation concrète de l'objet (Robj). Il faut donc effectuer un transtypage (cast) vers l'interface RobjInt.
Question 5 - Concepts de messagerie JMS
Voici le tableau complété pour les deux modèles de l'API Java Message Service (JMS) :
| JMS parent | Modèle Point-to-Point (P2P) | Modèle Publish-Subscribe (Pub/Sub) |
|---|---|---|
| Destination | Queue |
Topic |
| Session | QueueSession |
TopicSession |
| MessageProducer | QueueSender |
TopicSender |
| MessageConsumer | QueueReceiver |
TopicReceiver |
Question 6 - Réception synchrone vs asynchrone pour un client MOM
- Réception synchrone : Le client demande explicitement le message (mode "pull"). L'appel est bloquant : le thread du client s'arrête et attend jusqu'à ce qu'un message soit disponible (ex: utilisation de la méthode
receive()). - Réception asynchrone : La distribution est gérée par le fournisseur (mode "push"). Le client enregistre un écouteur (un
MessageListeneravec une méthodeonMessage()) et continue son exécution. Le fournisseur invoque automatiquement l'écouteur lorsqu'un message arrive.
Question 7 - Relation entre JMS, JORAM et Scalagent
- JMS (Java Message Service) : C'est une spécification (une API standard de Java) qui définit comment les clients doivent interagir avec un intergiciel orienté messages (MOM).
- JORAM : C'est une implémentation open-source concrète de l'API JMS.
- Scalagent : C'est l'entreprise/l'organisation (Scalagent Distributed Technologies) qui a développé et maintient l'implémentation JORAM basée sur une architecture d'agents distribués.
Exercice 2 : RPC
Question 1 - Interfaces RPCL (Tableau.x et RTable.x)
Note : Le code RPCL fourni dans le corrigé source contient de graves erreurs de syntaxe empêchant la compilation par rpcgen (comme struct string chaine <25> ou Typedef Info ligne ;). Voici la version syntaxiquement correcte et fonctionnelle.
Interface pour les employés (Tableau.x) :
/* Fichier Tableau.x - Gestion complète des vols */
typedef string chaine<25>;
/* Définition du type Time (souvent représenté par un long UNIX) */
typedef long Time;
struct ligne {
chaine RefVol;
chaine compagnie;
chaine dest_dep;
Time heure;
chaine etat;
};
typedef struct ligne Info;
program GVOLS {
version GVOLS_VERS {
void VNULL(void) = 0;
int AddRow(Info ligne) = 1;
int DeleteRow(string Ref_vol) = 2;
Time FindH(string Ref_vol) = 3;
} = 1;
} = 0x23456789;
Interface pour les clients (RTable.x) :
/* Fichier RTable.x - Consultation des vols uniquement */
typedef string chaine<25>;
typedef long Time;
program RVOLS {
version RVOLS_VERS {
void VNULL(void) = 0;
Time FindH(string Ref_vol) = 1;
} = 1;
} = 0x34567891;
Question 2 - Utilité du fichier RTable_xdr.c
Le fichier RTable_xdr.c est généré automatiquement par le compilateur rpcgen à partir du fichier RTable.x. Il contient les fonctions de filtres XDR (eXternal Data Representation). Ces fonctions servent à sérialiser (encoder) et désérialiser (décoder) les structures de données complexes pour qu'elles puissent transiter de manière standardisée sur le réseau, indépendamment de l'architecture des machines clientes et serveurs (gestion du boutisme/endianness, taille des entiers, etc.).
Question 3 - Prototype de la fonction FindH dans le serveur
En C avec RPC, la fonction implémentée côté serveur se voit attribuer un suffixe indiquant sa version (_1) et le fait qu'elle s'exécute côté serveur (_svc). Les paramètres d'entrée sont toujours passés par pointeur.
Time * findh_1_svc(char **ref_vol, struct svc_req *rqstp);
(Le corrigé de la source utilise string *vol, mais en C standard généré par rpcgen, un type RPC string se traduit par un char *. Son passage par référence donne donc un pointeur sur pointeur de caractère : char **.)
Question 4 - Appel distant depuis un client
Voici le code C qu'un client doit exécuter pour se connecter et appeler la fonction :
#include "RTable.h" /* Généré par rpcgen */
void consulter_heure(char *host) {
CLIENT *clnt;
Time *resultat;
char *ref_vol = "TU_21537";
/* 1. Création du client et connexion au serveur RPC */
clnt = clnt_create(host, RVOLS, RVOLS_VERS, "tcp");
if (clnt == NULL) {
clnt_pcreateerror(host);
exit(1);
}
/* 2. Appel distant */
resultat = findh_1(&ref_vol, clnt);
if (resultat == (Time *) NULL) {
clnt_perror(clnt, "Erreur lors de l'appel RPC");
exit(1);
}
/* Traitement du résultat ici */
clnt_destroy(clnt);
}
Question 5 - Modification du serveur pour FindBox
Pour ajouter une fonction sans casser la compatibilité avec les clients existants, il faut créer une nouvelle version (version 2) dans le programme RPC.
Nouveau RTable.x :
typedef string chaine<25>;
typedef long Time;
program RVOLS {
version RVOLS_VERS {
void VNULL(void) = 0;
Time FindH(string Ref_vol) = 1;
} = 1;
version RVOLS_VERS2 {
void VNULL(void) = 0;
Time FindH(string Ref_vol) = 1;
int FindBox(string name) = 2;
} = 2;
} = 0x34567891;
Explication de l'appel client :
Un client souhaitant utiliser les deux fonctions simultanément créera une instance (un handle) de communication CLIENT ciblant spécifiquement la version 2 (RVOLS_VERS2). Il pourra ainsi appeler consécutivement findh_2(&ref_vol, clnt) et findbox_2(&destination, clnt) au travers de la même connexion. Côté serveur, pour éviter la duplication de code, la fonction findh_2_svc appellera simplement la logique métier de findh_1_svc.
Exercice 3 : Réservation de chambre à distance par RMI
Question 1 - Conditions pour un accès distant et concurrent
Pour assurer un accès distant via RMI, les méthodes ReserverChambre et AnnulerReservation doivent lever l'exception java.rmi.RemoteException. Pour gérer l'accès concurrent (éviter que deux clients réservent la même chambre au même moment), ces méthodes doivent être déclarées avec le mot-clé synchronized dans l'implémentation du serveur, garantissant l'exclusion mutuelle.
Question 2 - Interface du service RMI
import java.rmi.Remote;
import java.rmi.RemoteException;
public interface ReservationChambre extends Remote {
public int ReserverChambre(Information inf) throws RemoteException;
public boolean AnnulerReservation(int ref) throws RemoteException;
public Information DetailsReservation(int ref) throws RemoteException;
}
Question 3 - Paramètre passé par valeur (Information)
- Condition : La classe
Informationdoit implémenter l'interfacejava.io.Serializable. Ainsi, son état pourra être converti en flux d'octets et transmis sur le réseau. - Fichiers class nécessaires côté serveur : Le serveur doit posséder
ReservationChambre.class(l'interface),ReservationChambreImpl.class(son implémentation), mais aussiInformation.classetInformationImpl.classafin de pouvoir désérialiser l'objet reçu et accéder à ses données.
Question 4 - Paramètre passé par référence
- Modifications sur l'objet : L'objet
Informationdevient un objet distant. Il doit implémenter une interface qui hérite dejava.rmi.Remoteet chaque méthode exposée doit leverRemoteException. Son implémentation doit soit hériter dejava.rmi.server.UnicastRemoteObject, soit être exportée manuellement viaUnicastRemoteObject.exportObject(this, 0). - Fichiers class nécessaires côté serveur : Le serveur a seulement besoin de
ReservationChambre.class,ReservationChambreImpl.classet de l'interfaceInformation.class. Il n'a pas besoin deInformationImpl.classcar il recevra uniquement un stub (une référence réseau) pointant vers l'objet résidant sur la machine cliente.
Question 5 - Meilleur choix d'implémentation
Le choix de la question 3 (passage par valeur via Sérialisation) est nettement meilleur.
Justification : Les données encapsulées dans l'objet Information (nom, dates, nombre de chambres) représentent un état statique, un formulaire. Si on le passait par référence, chaque fois que le serveur voudrait lire un champ (ex: inf.getNom()), cela déclencherait un nouvel appel réseau vers le client, augmentant drastiquement la latence, la charge réseau, et créant un point de défaillance si le client se déconnecte pendant le traitement. Le passage par copie permet au serveur de traiter la réservation localement et rapidement.
Question 6 - Code du client RMI
Note : Le code du corrigé original était truffé d'erreurs Java (variables non déclarées, fautes de frappe, classes inexistantes). Voici le code corrigé, compilable et fonctionnel.
import java.rmi.Naming;
public class ReservationClient {
public static void main(String args[]) {
try {
// 1. Récupération d'un stub sur l'objet serveur via le registre RMI
ReservationChambre reservationObj = (ReservationChambre) Naming.lookup("rmi://machineServeur/Reservation");
// 2. Création de l'objet Information (qui doit être Serializable)
// On suppose que InformationImpl implémente l'interface Information
Information inf = new InformationImpl("Dupont", 1, 3, 85.5, "2014-06-15");
// 3. Appel distant
int ref = reservationObj.ReserverChambre(inf);
// 4. Affichage du résultat
if (ref != 0) {
System.out.println("La référence de réservation est : " + ref);
} else {
System.out.println("Echec de la réservation.");
}
} catch (Exception e) {
System.err.println("Erreur côté client : " + e.getMessage());
e.printStackTrace();
}
}
}
Question 7 - Lieu d'exécution de la méthode getdate()
(Bien que cette question n'apparaisse pas explicitement dans l'énoncé source initial, elle figure dans le corrigé fourni).
Si on considère le choix de la question 3 (passage par valeur), la méthode getdate() sera exécutée par la JVM du serveur.
Justification : L'objet Information entier a été sérialisé par le client, transmis sur le réseau, et désérialisé par le serveur. Le serveur possède désormais un clone local de l'objet. Lorsqu'il invoque getdate(), l'exécution se fait entièrement dans sa propre mémoire locale, sans aucune communication réseau retour vers le client.
Méthode
Pour réussir un examen de Systèmes et Applications Répartis, la clé n'est pas d'apprendre du code par cœur, mais de maîtriser la mécanique réseau sous-jacente.
- Identifiez toujours où s'exécute le code : Face à un appel de fonction (RPC ou RMI), demandez-vous systématiquement : "Où suis-je ? Sur le client ou sur le serveur ? Les paramètres voyagent-ils sur le réseau sous forme de copie (valeur) ou de pointeur distant (référence) ?".
- Faites attention aux contraintes des intergiciels : RMI nécessite la sérialisation, des interfaces spécifiques (
Remote) et la gestion des exceptions (RemoteException). Omettre l'un de ces éléments est une erreur fatale. RPC demande une définition stricte des types dans un langage IDL agnostique. - Validez vos syntaxes d'examen : Lorsque vous rédigez du code sur papier, concentrez-vous sur la logique des blocs de gestion d'erreur (les
try/catchen Java, la vérification desNULLen C) et sur les signatures de connexion (commeNaming.lookupouclnt_create). C'est là que les correcteurs évaluent votre compréhension de la robustesse des systèmes distribués.
Commentaires
Aucun commentaire pour le moment. Posez la première question.