Programmation Client Serveur
P ROF. G UE RMAH H AT I M
EMAIL: [email protected]
Année Universitaire: 2024-2025
RMI Et les objets distribués
2
Introduction
▪ Un objet peut demander à un autre objet de faire un travail (généralement
spécialisé).
Machine locale Machine distante
obj_dist.methode(); obj_dist
▪ Contraintes:
◦ L’objet qui fait le travail n’est pas localisé sur la même Machine.
◦ L’objet peut ne pas être implémenté en Java.
3
Introduction
▪ Objectifs : créer un système distribué capable de:
◦ Invoquer une méthode d’un objet distant (obj_dist) de la même manière que s’il était local.
◦ Demander à un service « dédié » de renvoyer l’adresse de l’obj_dist sans savoir où l’objet se
trouve
obj_dist =ServiceDeNoms.rechercher("monObjet");
Service de noms
◦ Passer un obj_dist en paramètre à une méthode (distante ou locale).
objetLocal.methode(obj_dist);
objDistant.methode(obj_dist);
◦ Récupérer le résultat d’un appel distant sous forme d’un nouvel objet qui aurait été créé sur la
machine distante
obj_dist = objDistant.methode() ;
4
Introduction
▪ Difficultés : comment implémenter ?
◦ En local : le programme « client » doit
o Traduire la requête dans un format intermédiaire pour la transmission.
o Envoyer les données de la requête au serveur.
Machine Locale Machine Distante
o Analyser la réponse et l’afficher à l’utilisateur.
Client Serveur
◦ A distance : le programme « serveur » doit
Envoi requête
o Analyser la requête.
o Evaluer la réponse.
o Formater la réponse pour la transmettre au client.
5
Pattern Proxy
▪ Objectif : Fournir un intermédiaire entre la partie cliente et un objet pour contrôler les accès à ce
dernier.
▪ Résultat : Le Design Pattern permet d'isoler le comportement lors de l'accès à un objet.
▪ Responsabilités
Abstraction : définit l'interface des classes Implémentation
et Proxy.
Implémentation : implémente l'interface. Cette classe définit
l'objet que l'objet Proxy représente.
Proxy : fournit un intermédiaire entre la partie cliente et
l'objet Implémentation. Cet intermédiaire peut avoir
plusieurs buts (synchronisation, contrôle d'accès, cache,
accès distant, ...).
La partie cliente appelle la méthode operation() de l'objet
Proxy.
6
Pattern Proxy
▪ Ajouter des représentants (proxys) pour faire ce travail
▪ Ni le client ni le serveur n’ont à se soucier de l’envoi des données dans le réseau ni de leur
analyse
MachineA MachineB
Client proxy proxy Serveur
Appelproxy Appelméthode
Envoi requête
localement localement
Retourrésultat
Retourréponse
Retourrésultat
7
RPC Middleware
▪ Le client appelle une procédure locale (souche – stub / proxy)
▪ La procédure locale utilise une connexion socket pour envoyer un identifiant de procédure et les paramètres au serveur
▪ Le serveur reçoit la requête grâce à un socket, extrait l’id de procédure et les paramètres (ceci est fait par un squelette – skeletton)
▪ Le squelette exécute la procédure et renvoie le résultat via le socket
Programme Stub (Client ) Skeletton(Server)
Librairie de Librairie de Programme
Client Communication Communication Serveur
Emballage Réception
Appel + +
Envoi Protocole Déballage
RPC Exécution
Protocole Procédure
Retour
Réception RPC Emballage
+ +
Déballage Envoi
8
RPC Middleware : Contrat
▪ Le contrat : formalise le dialogue entre le client et le serveur et permet au
interface test
client et au serveur d’avoir la même compréhension des échanges effectués. Il {
permet de répondre aux questions : int param;
…
o que transmet-on ?
o où envoie-t-on les données ?
o qui reçoit les données ? Compilateur IDL
o comment sait-on que le travail est terminé ?
▪ Compilateur IDL : Génère le stub et le skeletton à partir d’un fichier
présentant l’interface des méthodes dans un format indépendant du langage
IDL Interface Definition Language (OSF IDL RPC pour la technologie RPC. ) Skeletton
Stubs Client
Serveur
▪ Couche de présentation XDR (eXternal Data Representation) : Format pivot
de représentation des données de types primitifs et structurés (tableaux,
tableaux de taille variable, structures…)
9
RPC Middleware
▪ Limitations :
o Pas de gestion des concepts objets (encapsulation, héritage, polymorphisme)
o Pas de services évolués : nommage …
▪ Successeurs :
o RMI : mono langage, multi plateforme
o CORBA : multi langage, multi plateforme
o COM : multi langage, mono plateforme (multi pour DCOM)
o SOAP / .NET / web services : multi langage, multi plateforme
10
CORBA
▪ Client et serveur peuvent être écrits en C, C++, Java ou
tout autre langage
▪ Utilise le protocole IIOP (Internet Inter-ORB Protocol) Application "Client" Application "Serveur"
pour communiquer entre les objets
Object reference Servant
▪ Interface de description qui spécifie les signatures des (référence d'objet) (implantation de l'objet)
méthodes et les types de données des objets. Un langage
spécial : IDL (Interface Definition Language) Stub Skeleton
IIOP IIOP
▪ Etapes de développement :
o Ecriture compilation de l'interface de l'objet en IDL Object Request Broker (ORB)
o Implantation de l'objet
Le dialogue CORBA : client, ORB et serveur
o Réalisation et Compilation de l'application serveur
o Réalisation et Compilation de l'application cliente
11
SOAP
▪ SOAP (Simple Object Access Protocol) est un protocole
d'échange d'information structurée dans l'implémentation
de services web bâti sur XML.
▪ Neutre vis-à-vis des langages de programmation
▪ L’interface de description est spécifiée dans un langage
spécial : WSDL
▪Le WSDL ou Web Services Description
Language (prononcez en sigle ou « Whiz-Deul ») est une
grammaire XML permettant de décrire un Service Web.
12
RMI
▪ RMI est une core API (intégré au JDK 1.1)
o 100 % Java, gratuit (différent de CORBA)
o Une version "orientée objet" de RPC
o Permet aux Objets Java Distants de communiquer Mais sans
écrire une seule ligne de code réseau
o RMI est suffisant car plus simple : Lorsque les objets
communicants sont implémentés en Java, la complexité et la
généralité de CORBA ou de SOAP les rendent plus difficile que
RMI.
▪ Caractéristiques de RMI
o RMI utilise directement les sockets
o RMI code ses échanges avec un protocole propriétaire : RMP
(Remote Method Protocol)
13
RMI : Principe d’utilisation
▪ L’objet client appelle les méthodes de l’objet distant JVM JVM
Programme client Programme serveur
o Bien entendu les paramètres doivent être envoyés d’une public class A{ public class B{
façon ou d’une autre à l’autre machine void f(){
void m(){
B o; Method
...
Call
o.m(); }
o Le serveur doit en être informé pour exécuter la méthode }
stub
et la valeur de retour doit être renvoyés.
▪ La terminologie objet client, objet serveur concerne un appel Network Socket Network Socket
distant : Un ordinateur peut être client pour un appel et
serveur pour un autre Network
o L’objet proxy qui se trouve sur le client est appelé stub :
Représentant local de l’objet distant.
14
RMI : Principe d’utilisation
▪ Le client utilise toujours des variables de type interface : Le client n’a pas de connaissance sur le type
d’implémentation.
interface Warehouse {
int getQuantity (String description) throws RemoteException;
Product getProduct(Customer cust) throws RemoteException; }
▪ A l’appel la variable faitréférence au stub
Warehouse centralWarehouse =…
//doit être lié à un objet courant d’un certain type
▪ La syntaxe reste la même que pour un appel local
int q = centralWarehouse.getQuantity("Super Cleaner");
▪ Les classes du stub et les objets associés sont créés automatiquement : La plupart des détails sont cachés au
programmeur, mais un certain nombre de techniques doivent être maitrisées
15
RMI : Fonctionnement
1. L'objet serveur est créé, si nécessaire il crée l’objet squelette (avant Java 2), puis le port
de communication est ouvert : Il faut Exposer l’OD via UniCastRemoteObject
2. L'objet serveur s'enregistre auprès du service de noms RMI via la classe Naming de sa
JVM (méthode bind ou rebind): Le Naming enregistre le nom de l’objet serveur et une
souche client (contenant l’@IP et le port de comm.) dans le rmiregistry
JVM JVM
Programme client Programme serveur
RMI Registry
Serveurde 2
Noms
OD
1
Serveur
stub d’objets UniCastRemoteObject
Network Socket Network Socket
Network
16
RMI : Fonctionnement
3. L'objet client fait appel au Naming de sa JVM pour localiser l'objet serveur (méthode
lookup)
4. Le Naming récupère la souche client de l'objet serveur, …
JVM JVM
Programme client Programme serveur
Naming.lookup() 3 RMI Registry
Serveurde
Noms
OD
4
Serveur
stub d’objets
Network Socket Network Socket
Network
17
RMI : Fonctionnement
5. Le stub récupère les paramètres de la méthode
6 . Le stub emballe les paramètres qu’il envoi au skeleton via le serveur d’objets
JVM JVM
Programme client Programme serveur
RMI Registry
5 Serveurde OD
Noms
6 Serveur 6
stub d’objets Skeleton
Network Socket Network Socket
Network
18
RMI : Fonctionnement
7. Le skeleton déballe les infos et fait appel à la méthode de l’OD
8 . Il renvoie le résultat après emballage
JVM JVM
Programme client Programme serveur
RMI Registry
Serveurde OD
8 Noms
7
8 Serveur 8
stub d’objets Skeleton
Network Socket Network Socket
Network
19
Etapes de développement
▪ Etape 1 : Définition de l'interface de l'objet distant :
o interface héritant de java.rmi.Remote
o Utiliser pour les méthodes : "throws java.rmi.RemoteException"
o paramètres de type simple, objets Sérialisables (implements Serializable) ou Distants (implements Remote)
▪ Etape 2: Ecrire une implémentation :
o Classe héritant de java.rmi.server.UnicastRemoteObject et implémentant l'interface précédente.
o Ecrire un main permettant l'enregistrement auprès du Naming
▪ Etape 3: Génération de la classe stub nécessaire au client et Ecriture du programme client
o utilisation du Naming pour trouver l'objet distant
o appel(s) de méthodes.
20
Remote Method Invocation
▪ Etape 1 : Définition de l'interface de l'objet distant
import java.rmi.*;
Produit.java
public interface Produit extends Remote {
String getDescription() throws RemoteException;
}
▪ Cette interface doit résider sur le client et le serveur
▪ Elle doit étendre “Remote”
▪ Ces méthodes doivent lancer une RemoteException puisque des problèmes réseau peuvent survenir.
21
Remote Method Invocation
▪ Etape 2 : Implémentation de l’objet distant
import java.rmi.*;
Produit.java
public class ProduitImpl extends UnicastRemoteObject implements Produit {
private String name;
public ProduitImpl(String n) throws RemoteException
{ name = n;
}
public String getDescription() throws RemoteException {
return " Je suis " + name + ". Achetemoi!";
}
22
Remote Method Invocation
Les classes RMI Object
▪ Il est possible de ne pas étendre
Remote
UnicastRemoteObject (héritage multiple par exemple)
▪ Dans ce cas, il faut :
RemoteObject classe abstraite :
▪ instancier manuellement les objets serveur définit uniquement les
etles passer à la méthode statique mécanismes de base pour la
communication entre les objets
exportObject() serveur et les stubs.
▪ Dans le constructeur de l’objet RemoteStub RemoteServer
serveur par exemple :
UnicastRemoteObject.exportObject(this,0);
→ (0 pour indiquer que n’importes quel port peut être utilisé classe concrète :
pour écouter les connexions client) UnicastRemoteObject Traitements
élémentaires pour un
objet distant.
23
Remote Method Invocation
▪ Etape 3 : Génération de la classe stub nécessaire au client
javac ProduitImpl.java
▪ JDK 1.2
o rmic –v1.2 ProductImpl
o Deux fichiers sont générés Fichier stub Product_Skel.class
▪ JDK 5.0
• Toutes les classes stub sont généréesautomatiquement
• La classe skeleton n’est plus nécessaire à partir deJDK1.2
▪ Lancement du serveur de nom (rmiregistry) : on peut aussi appeler dans le main serveur
LocateRegistry.createRegistry(1099);
24
RMI Registry
▪ Le registre de noms RMI doit s'exécuter avant de pouvoir enregistrer un objet ou obtenir une référence.
▪ Le registre de noms RMI peut être lancé :
o par start rmiregistry
o Ou dynamiquement dans la classe qui enregistrel'objet.
java.rmi.registry.LocateRegistry.createRegistry(1099);
Naming.rebind(url, od);
▪ L’objet UnicastRemoteObject réside sur le serveur. Il doit être actif lorsqu’un service est demandé et doit
être joignable à travers le protocole TCP/IP : Nous créons des objets d’une classe qui étend UnicastRemoteObject,
un thread séparé est alors lancé, il garde le programme indéfiniment en vie .
25
RMI : Programme Serveur
AP I java.rmi.Naming 1.1
▪ static void bind(String name, Remoteobj)
binds name to the remote object obj. Throws a AlreadyBoundException if the
object is already bound.
▪ static void unbind(String name)
unbinds the name. Throws a NotBoundException if the name is not currently
bound.
▪ static void rebind(String name, Remoteobj)
binds name to the remote object obj. replaces an existing binding.
▪ static String[] list(String url)
returns an array of strings of the URLs in the registry located at the given URL.
The array contains a snapshot of the names present in the registry.
26
RMI : Programme Serveur
import java.rmi.*; import ProduitServer.java
java.rmi.server.*;
public class ProduitServer {
public static void main(String args[]) {
System.out.println("Construction des implémentations");
ProduitImpl ref1 = new ProduitImpl("Sony 40p");
ProduitImpl ref2 = new ProduitImpl("ZapXpress Microwave");
System.out.println("Binding implementations to registry");
Naming.rebind("television", ref1);
Naming.rebind("microwave", ref2);
System.out.println("Enregistrement effectué attente de clients...");
• Le serveur enregistre les objets auprès du serveur de noms en donnant un nom unique et une reference à
chaque objet.
• rebind() à la place de bind() pour éviter l’erreur AlreadyBoundExceptionlorsque l’entrée existe déjà
27
Gestionnaire de Sécurité
▪ Il faut donc utiliser un gestionnaire de sécurité dans les applications clientes RMI.
▪ Le comportement par défaut lors de l'exécution d'une application Java est qu’aucun gestionnaire
de sécurité n’est installé.
▪ Le gestionnaire de sécurité par défaut pour RMI est
▪ java.rmi.RMISecurityManager Deprecated à partir de java 9
▪ System.setSecurity(RMISecurityManager)
▪ Les Applets, elles, installent un gestionnaire de sécurité assez restrictif :
AppletSecurityManager
▪ Pour des applications spécialisées, les programmeurs peuvent utiliser leur propre
«ClassLoader » et « SecurityManager » mais pour un usage normal, ceux fournis par
RMI suffisent
28
RMI : Programme Client
import java.rmi.*; ProduitClient.java
public class ProduitClient {
public static void main(String args[]) {
System.setSecurityManager( new RMISecurityManager());
▪ Par défaut, RMISecurityManager empêche tout le code dans le programme d'établir des connexions réseau.
▪Mais ce programme a besoin de connexions réseau :
o Pour atteindre le « RMI Registry »
o Pour contacter les « objets serveur »
o Lorsque le client est déployé, il a aussi besoin de permissions pour charger ces classes de stub.
▪ Donc, Java exige que nous écrivons un "policy file”
29
RMI : Programme Client
Policy File : « client.policy »
grant
{ permission java.net.SocketPermission
"*:1024-65535", "connect";
};
▪Autorise l’application à faire des connections réseau sur un port supérieur à 1024. (Le port RMI est 1099 par
défaut)
▪A l’exécution du client, on doit fixer une propriété système :
javac ProduitClient.java
java –Djava.security.policy=client.policy ProduitClient
30
RMI : Programme Client
Mécanismes de sécurité alternatifs : De nos jours, les configurations de sécurité sont généralement gérées par
d'autres moyens, tels que :
• L'utilisation des politiques de sécurité java.security pour configurer les autorisations.
• L'exploitation des gestionnaires de sécurité fournis par des outils et frameworks modernes.
• L'emploi d'autres fonctionnalités de sécurité, comme SSL (Secure Sockets Layer) /TLS (Transport Layer
Security) pour sécuriser les communications.
Pour configurer les autorisations dans RMI (Remote Method Invocation) à l'aide de politiques de sécurité
java.security:
➢ Créer un fichier de politique de sécurité grant { // Autoriser l'accès en lecture/écriture au fichier "test.txt"
permission java.io.FilePermission "test.txt", "read,write";
// Autoriser l'accès à l'API RMI pour charger les classes
permission java.net.SocketPermission "localhost:1099", "connect,accept,resolve";
// Autoriser l'accès au système de fichiers pour des classes spécifiques
permission java.security.AllPermission;};
➢ Lancer votre application RMI avec le fichier de politique :
java -Djava.security.manager -Djava.security.policy=rmi.policy MyRMIClient
31
RMI : Programme Client
String url = "rmi://localhost/"; ProduitClient.java
//stub
Produit c1 = (Produit)Naming.lookup(url + "television");
Produit c2 = (Produit)Naming.lookup(url + "microwave");
System.out.println(c1.getDescription());
System.out.println(c2.getDescription());
▪ Le serveur de noms fournit la méthode statique lookup(url) pour localiser un objet serveur. L’URL RMI :
"rmi://serveur:[port]/objet"
▪ c1 et c2 ne font pas référence à des objets sur le serveur. Ils font plutôt référence à un stub qui doit exister sur
le client.
32
RMI : Recapitulatif
Récapitulatif des activités
1. Compiler les fichiers java
javac *.java
2. Avant JDK1.5: générer les stub
rmic –v1.2 ProduitImpl
3. Lancer le RMI registry (serveur de nom)
start rmiregistry
4. Lancer le serveur
start java ProduitServer
5. Exécuter le client
java –Djava.security.policy=client.policy ProduitClient
33
RMI : Recapitulatif
Déploiement
─ Préparer le déploiement (JDK1.5)
─ Trois dossiers
server/
ProductServer.class
ProductImpl.class
Product.class
client/
ProductClient.class
Product.class
client.policy
download/
Product.class
download contient les classes utilisées par
RMI registry, le client et le serveur.
34
Exercice :
▪ On souhaite rendre une Méthode HelloWorld accessible à distance de manière à ce qu’elles
définissent l’interface entre le client et le serveur : Ecrire cette interface. (Respectez les règles
syntaxiques que doit suivre une interface Java RMI) et les programmes client et Serveur.
35