Invocación de Métodos Remotos Arquitectura Cliente/Servidor

Anuncio
Arquitectura Cliente/Servidor
Request
Cliente
Invocación de Métodos Remotos
RMI: Remote Method Invocation
¿ Cómo permitir comunicación entre objetos situados
en diferentes máquinas ?
¿ Cómo llamar a métodos de programas que corren en
máquinas diferentes ?
Prof. Wílmer Pereira
Universidad Simón Bolívar
Llamadas a Métodos Remotos
El
El cliente
cliente necesita
necesita hacer
hacer transparente
transparente la
la llamada
llamada
aa métodos
métodos remotos
remotos =>
=> stubs
stubs
? El stub paquetiza los parámetros (marshalling) y los
codifica en un formato estándar independientes de los
procesadores involucrados en la aplicación cliente/servidor
Big-endian
? El stub da la impresión de localidad al cliente, asegurando
transparencia
? El servidor asegura:
•
•
•
•
desempaqueta los parámetros (unmarshalling),
llama al método invocado,
paquetiza los valores de retorno o excepción (marshalling)
envía información al cliente.
Servidor
Reply
La
La invocación
invocación del
del servicio
servicio remoto
remoto es
es aa partir
partir de
de un
un objeto
objeto
(creado
(creado en
en el
el cliente)
cliente) que
que llama
llama aa un
un método
método
(implementado
(implementado en
en el
el servidor)
servidor)
La
La idea
idea es
es tener
tener un
un contexto
contexto de
de ejecución
ejecución parecido
parecido al
al local
local
bajo
bajo una
una arquitectura
arquitectura cliente/servidor
cliente/servidor
Principios de una llamada remota
Llamada al método remoto desde el cliente:
centralWarehouse.getQuantity(“SuperSucket 100”);
Interfaz común al cliente y servidor:
interface Warehouse {
public int getQuantity(String description)
throws RemoteException:
.
.
.
}
Declaración del objeto local :
Warehouse centralWarehouse = ...;
1
Carga dinámica de clases
Ejemplo: Interfaz e implantación
Interfaz compartida por el cliente y el servidor:
El
El cliente
cliente requiere
requiere cargar
cargar
las
las clases
clases yy excepciones
excepciones
que
que el
el servidor
servidor cambie,
cambie,
según
según su
su evolución
evolución
interface Product extends Remote {
public String getDescription()
throws RemoteException:
}
Carga dinámica con el
ClassLoader
Llamada del cliente:
Product p;
String d=p.getDescription();
Sin embargo ...
esto implica problemas de seguridad
Implantación del método remoto :
public class ProductImpl extends UnicastRemoteException
implements Product {
public ProductImpl(String d)
throws RemoteException
{ descr=d; }
public String getDescription()
throws RemoteException
{ return “Esto es un”+descr; }
private String descr;
}
En consecuencia ...
se necesita al security manager para impedir
llegada de virus a través de los stubs
Jerarquía de clases
Convenciones RMI
Sufijos
Object
Sin:
Remote
RemoteObject
Interfaz común cliente/servidor (Product)
Impl:
Clase del servidor que implemente la interfaz (ProductImpl )
Server:
Clase que crea los objetos servidores (ProductServer )
RemoteStub
RemoteServer
Client:
Clase que llama a métodos remotos (ProductClient)
_Stub
Subclase generada automáticamente por rmic (Product_Stub)
UnicastRemoteObject
SUN propone la clase MulticastRemote para manejar
objetos replicados en múltiples servidores
rmic genera el stub que es usado por el cliente
rmic
rmic ProductImpl
ProductImpl
2
Servicio de registro de stubs
El
El servidor
servidor carga
carga los
los stubs
stubs por
por cada
cada uno
uno de
de sus
sus objetos
objetos
(generado
(generado por
por rmic)
rmic) para
para que
que pueda
pueda ser
ser
descargado
descargado por
por cada
cada objeto
objeto del
del cliente
cliente
Carga el stub en servidor de registro (bind)
//servidor
ProductImpl pl = new ProductImpl();
Naming.bind(“toaster”,pl);
Descarga el stub del servidor de registro (lookup)
//cliente
Product p = (Product) Naming.lookup
(“rmic://www.ldc.usb.ve/toaster”);
? El puerto por defecto es el 1099
? La aplicación servidor debe correr en la misma máquina del
servidor de registro (por razones de seguridad)
Código de ejemplo (Implantación del
Servidor)
import java.rmi.*;
import java.rmi.server*;
public class ProductImpl extends UnicastRemoteObject
implements Product {
public ProductImpl(String n) throws RemoteException
{ name = n; }
public String getDescription() throws RemoteException
{ return “Est es un “+name; }
private String name;
}
? A partir de esta clase se crean los stubs que deben cargarse en el
servidor de registro (bind) y ser bajados por el cliente (lookup)
? Los métodos que llama el cliente están implantados en esta clase
Código de ejemplo ( Servidor)
import java.rmi.*;
import java.rmi.server*;
public class ProductServer {
public static void main(String args[]) {
try {
ProductImpl p1 = new ProductImpl(“Black Toaster”);
ProductImpl p2 = new ProductImpl(“Express Oven”);
Naming.rebind(“toaster”,p1);
Naming.rebind(“oven”,p2);
} catch (Exception e) {
System.out.println(“Error: “+e);
}
}
}
? Antes de correr el servidor debe levantarse el servidor de registro
? El servidor queda levantado indefinidamente con un thread que
lanza el objeto de UnicastRemoteObject
Código de ejemplo (Interfaz)
import java.rmi.*;
public interface Product extends Remote {
String getDescription() throws RemoteException;
}
? La interfaz debe estar tanto en el servidor como en el cliente de la
aplicación
? Inicialmente se instala el servidor de registro
rmiregistry
rmiregistry &&
? Se ejecuta el servidor de la aplicación para cargar los stubs en el
servidor de registro que fue instalado antes
java
java ProductServer
ProductServer
3
Codigo de ejemplo (Cliente)
import java.rmi.*;
import java.rmi.server*;
public class ProductClient {
public static void main(String args[]) {
System.setSecurityManager(new RMISecurityMananger());
String url = “rmi://localhost/”
try {
Product c1 = (Product)Naming.lookup(url+”toaster”);
Product c2 = (Product)Naming.lookup(url+”oven”);
System.out.println(c1.getdescription());
System.out.println(c2.getdescription());
} catch (Exception e) {
System.out.println(“Error: “+e);
}
System.exit(0);
}
}
El programa instala el manejador de seguridad y se baja los stubs
(uno por cada objeto del cliente) para poder llamar al método remoto
Correr la aplicación (localmente)
? Compilar fuentes en el servidor
javac Product*.java
? Correr rmic para generar los stubs
rmic ProductImpl
? Instalar el servidor de registro
rmiregistry &
? Instalar el servidor
java ProductServer &
? Correr el cliente
java –Djava.security.policy=cliente.policy ProductClient
Directorios y archivos
Servidor
Cliente
ProductServer.class
ProductClient.class
ProductImpl.class
Product.class
Product.class
client.policy
ProductImpl_Stub.class
Download
ProductImpl_Stub.class
Product.class
Políticas de seguridad de la
aplicación
El
Elmanejador
manejadorde
deseguridad
seguridadrestringe
restringeaacualquier
cualquier
Código
Códigode
deser
sercargado
cargadodesde
desdeelelcliente
cliente
Sin embargo el cliente necesita conexión para:
? Bajar los stubs del servidor de registro
? Acceder a los objetos remotos para llamar a los métodos remotos
En consecuencia se debe suplir un archivo de seguridad:
cliente.policy
grant {
permission java.net.SocketPermission “*:1024-65535”,”connect”;
};
java
java ProductClient
ProductClient -Djava.security.policy=client.policy
-Djava.security.policy=client.policy
Correr la aplicación (remotamente)
Para bajar los stubs debe haber un servidor Web
corriendo en el servidor
? Se puede instalar un servidor Web sencillo desde
ftp://java.sun.com/pub/jdk1.1/rmi/class- server.zip
? Mover el directorio download al directorio del servidor
Web
? Cambiar el client.policy para conectarse al servidor
de registro, implantaciones del servidor y el puerto del
HTTP. Todo esto indicando la máquina remota
grant {
permission java.net.SocketPermission
“servok.ldc.usb.ve:1024-65535”,”connect”;
permission java.net.SocketPermission
“servok.ldc.usb.ve:80”,”connect”;
};
4
Aplicación con servidor Web
? Levantar el rmiregistry en un shell sin classpath y
desde un directorio sin .class
? Desde un shell levantar el servidor dando el URL del directorio
download
java
javaProductServer
ProductServer–Djava.rmi.server.codebase=http://localhost/download/
–Djava.rmi.server.codebase=http://localhost/download/
? Modificar el URL en el cliente para poder acceder al servidor
remoto
String url = “rmi://servok.ldc.usb.ve/”
Product cl= (Product)Naming.lookup(url+”tostador”);
? Correr el cliente indicando las nuevas políticas de seguridad
java
javaProductClient
ProductClient–Djava.security.policy=client.policy
–Djava.security.policy=client.policy
Observaciones del enfoque RMI
? Este enfoque permite ejecutar concurrente el mismo método por varios
clientes. Sin embargo si se requiere exclusión mutua, sobre el m étodo,
se puede utilizar la primitiva syncronize.
? No se tiene acceso a los mismos descriptores de I/O entre el cliente y
el servidor.
? Los stubs se encargan de los parámetros y lo único no permitido en los
métodos remotos, es el pasaje de parámetros por referencia. La única
condición es que los objetos pasados como parámetros deben
implementar la interfaz Serializable.
? No se pueden sobrescribir los métodos equals, clone y paint.
Deben escribirse métodos propios para realizar dichas tareas.
? Cuando se implementan la aplicación sobre applets, no se puede
modificar las restricciones de seguridad que impone el browser.
? Es conveniente usar levantar el servidor de registro (rmiregistry)
desde el servidor para evitar su proliferación en varias máquinas. El
comando es:
LocateRegistry.createRegistry(port);
5
Descargar