Paso de mensajes con RMI
Programación distribuida
No existe memoria común, hay comunicaciones, no existe un estado global del sistema, grado de transparencia, escalablas y reconfigurables.
Modelos de programación distribuida
- Paso de mensajes (
send
yreceive
) - RPC
- Stubs cliente y servidor
- Visión en java es RMI
- Objetos distribuidos
- DCOM de Microsoft
- Jini de SUN
- CORBA de OMG
Modelos de paso de mensajes
Mecanismo para comunicar y sincronizar entidades concurrentes que no pueden o no quieren compartir memoria. Se hace uso de llamadas send
y receive
.
Tipología de llamadas:
- BLoqueadas - no bloqueadas
- Almacenadas - no almacenadas
- Fiables - no fiables
En UNIX, pipes
con y sin nombres.
En Java:
- Sockets, clases
Socket
yServerSocket
- Canales, CTJ (communicating Threads for Java)
Modelo Romote Procedure Call (RPC)
Mayor nivel de abstracción, llamadas a procedimientos local o remoto indistintamente.
Necesita de stubs/skeletons (ocultamiento), y registro del serviio (servidor de nombres).
En UNIX:
- Biblioteca
rpc.h
- Representación estándar XDR
- Automatización parcial, especificación-compilador
rpcgen
En java:
- Objetos remotos, serialización
- Paquete
java.rmi
- Automatización parcial, interfaz-compilador
rmic
Nuestro objetivo será efectuar llamadas como si tuvieran carácter local a un método remoto, enmascarando los aspectos relativos a comunicaciones.
Stubs
Efectúan el marshalling/unmarshalling de parámetros, bloquean al cliente a la espera del resultado. Transparecia de ejecución remota. Interface con el nivel de red (TCP, UDP).
Generación
De forma manual o de forma automática.
Especificación formal de interfaz, software específico, rpcgen
(C-UNIX) / rmic
(Java).
Nota sobre RPC en C
Especificación de la interfaz del servidor remoto en un fichero de especificación .x
/* rand.x */
program RAND_PROG{
version RAND_VER{
void inicia_aleatorio(long)=1;
double obtener_aleat(void)=2;
}=1;
}=0x3111111;
Generación automática de resguardos, rpcgen rand.x
Distribuir y compilar ficheros entre las máquinas implicadas.
Necesario utilizar representación XDR. Biblioteca xdr.h
.
RMI en Java
Permite disponer de objetos distribuidos utilizando Java. Un objeto distribuido se ejecuta en una JVM diferente o remota.
Objetivo, lograr una referencia al objeto remoto que permita utilizarlo como si el objeto se estuviera ejecutando sobre la JVM local.
Similar a RPC, si bien el nivel de abstracción es más alto, se puede generalizar a otros lenguajes utilizando JNI. RMI pasa los parámetros y valores de retorno utilizando serialización de objetos.
RPC | RMI |
---|---|
Carácter y estructura de diseño procideimental | Carácter y estructura de diseño orientada a objetos |
Es dependiente del lenguaje | Es dependiente del lenguaje |
Utiliza la representación externa de datos XDR | Utiliza la serialización de objetos en Java |
El uso de punteros requiere el manejo explícito de los mismos | El uso de referencias a objetos locales y remotos es automático |
NO hay movilidad de código | El código es móvil, mediante el uso de bytecodes |
Llamadas locales vs. llamadas remotas
Un objeto remoto es aquél que se ejecuta en una JVM diferente situada potencialente en un host distinto.
RMI es la acción de invocar a un método de la interfaz de un objeto remoto.
// ejemplo de llamada a metodo local
int dato;
dato = Suma (x,y);
//ejemplo de llamada a metodo remoto (no completo)
IEjemploRMI1 ORemoto =
(IEjemploRMI1)Naming.lookup("//sargo:2005/EjemploRMI1";
ORemoto.Suma(x,y);
Arquitectura RMI
-
Servidor:
- Debe extender
RemoteObject
- Debe implementar una interfaz diseñada previamente
- Debe tener como mínimo un constructor (nulo) que lance una excepción
RemoteException
- El método main debe lanzar un gestor de seguridad, así mismo éste crea los objetos remotos
- Debe extender
-
Cliente:
- De objetos remotos se comunican con interfaces remotas (diseñadas antes de), estos son pasados por referencia
- Los que llamen a métodos remotos deben manejar excepciones
El compilador de RMI (rmic) genera el stub y el skeleton.
Fases de diseño de RMI
- Escribir el fichero de la interfaz remota (public y extender de
Remote
) - Declarar todos los métodos que el servidor remoto ofrece, pero NO los implementa. Se indica nombre, parámentros y topo de retorno.
- Todos los métodos de la interfaz remota lanzan obligatoriamente la excepción
RemoteException
- El propósito de la interface es ocultar la implementación de los aspectos relativos a los métodos remotos, de esta forma, cuando el cliente logra una referencia a un objeto remoto, en realidad obtiene una referencia a una interfaz
- Los clientes envían sus mensajes a los métodos de la interfaz
/**
* Ejemplo de implementacion del interfaz remoto para un RMI
*/
import java.rmi.*;
import java.rmi.server.*;
import java.rmi.registry.*;
import java.net.*;
// el servidor debe siempre extender esta clase
// el servidor debe simpre implementar la interfaz
// remota definida con caracter previo
public class EjemploRMI1 extends UnicastRemoteObject implements IEjemploRMI1 {
public int Suma(int x, int y) throws RemoteException{
return x + y;
}
public int Resta(int x, int y) throws RemoteException {
return x - y;
}
public int Producto(int x, int y) throws RemoteException {
return x * y;
}
public float Cociente(int x, int y) throws RemoteException {
if (y == 0) return 1 f;
else return x / y;
}
//es necesario que haya un constructor (nulo) como minimo, ya que debe lanzar RemoteException
public EjemploRMI1() throws RemoteException {
//super(); invoca automaticamente al constructor de la superclase
}
//el metodo main siguiente realiza el registro del servicio
public static void main(String[] args) throws RemoteException {
// crea e instala un gestor de seguridad que soporte RMI.
// el usado es distribuido con JDK. Otros son posibles.
// En esta ocasion trabajamos sin el.
// System.setSecurityManager(
// new RMISecurityManager());
//Se crea el objeto remoto. Podriamos crear mas si interesa.
IEjemploRMI1 ORemoto = new EjemploRMI1();
//Se registra el servicio
Naming.bind("Servidor", ORemoto);
System.out.println("Servidor Remoto Preparado");
}
}
Stub y Skeleton
Es necesario que en la máquina remota donde se aloje el servidor se sitúen también los ficheros stub y skeleton. Con todo ello disponible, se lanza el servidor llamando a JVM del host remoto, previo registro en un DNS.
Registro
Método Naming.bind("Servidor", ORemoto);
para registrar el objeto remoto creado requiere que el servidor de nombres esté activo. Dicho servidor se activa con start rmiregistry
en Win32, o rmiregistry &
en Unix.
Se puede indicar como parámetro el puerto que escucha, si no se indica, por defecto es el puerto 1099. El parámetro puede ser el nombre de un host como por ejemplo:
Naming.bind("//sargo.uca.es:2005/Servidor", ORemoto);
Cliente
El objeto cliente procede siempre creando un objeto de interfaz remota.
Posteriormente efectúa una llamada al método Naming.lookup
cuyo parámetro es el nombre y puerto del host remoto junto con el nombre del servidor.
Naming.lookup
devuelve una referencia que se convierte a una referencia a la interfaz remota.
A partir de aquí, a través de esa referencia el programador puede invocar todos los métodos de esa interfaz remota como si fueran referencias a objetos en la JVM local.
// Ejemplo de implementacion de un cliente para RMI
import java.rmi.*;
import java.rmi.registry.*;
public class ClienteEjemploRMI1 {
public static void main(String[] args) throws Exception {
int a = 10; int b = -10;
//En esta ocasion trabajamos sin gestor de seguridad //System.setSecurityManager(new RMISecurityManager());
//Se obtiene una referencia a la interfaz del objeto remoto //SIEMPRE debe convertirse el retorno del metodo Naming.lookup //a un objeto de interfaz remoto
IEjemploRMI1 RefObRemoto = (IEjemploRMI1) Naming.lookup("//localhost/Servidor");
System.out.println(RefObRemoto.Suma(a, b));
System.out.println(RefObRemoto.Resta(a, b));
System.out.println(RefObRemoto.Producto(a, b));
System.out.println(RefObRemoto.Cociente(a, b));
}
}
Evoluciones reseñables
A partir del JDK 1.2 la implementación de RMI no necesita skeletons, el stub estará en ambos lados. A partir del JDK 1.5 se incorpora Generación dinámica de resguardos.
Características avanzadas
Serialización de objetos
Serializar un objeto es convertirlo en una cadena de bits, posteriormente restaurada en el objeto original. Es útil para enviar objetos complejos en RMI.
Los tipos primitivos se serializan automáticamente, las clases contenedoras también. Los objetos complejos deben implementar la interfaz Serializable
(es un flag) para poder ser serializados.
Gestión de seguridad(policytool)
Java tiene en cuenta la seguridad, lo ajustamos de la siguiente forma:
System.setSecurityManager(new RMISecurityManager());
Clase RMISecurityManager
Programador ajusta la seguridad mediante la clase Policy
Policy.getPolicy()
permite conocer la seguridad actual.Policy.setPolicy()
permite fijar nueva política- Seguridad reside en fichero específico
Java 2 incorpora una herramienta visual: policytool
Ajuste de la política de seguridad, crearlas con policytool
.
Para activarlas:
- Podemos ejecutar ajustando la política con
java -Djava.security=fichero.policy servidor|cliente
- Creando un objeto
RMISecurityManager
y ajustarSetSecurityManager
sobre el objeto creado.
Callback del cliente
Si el servidor RMI debe notificar eventos a clientes, la arquitectura es inapropiada. La alternativa estándar es el sondeo (polling), donde cliente:
Iservidor RefRemota = (IServidor) Naming.lookup (URL);
while (!(Ref.Remota.Evento.Esperado())){}
Características
Clientes interesados se registran en un objeto servidor para que les sea notificado un evento, cuando el evento se produce, el objeto servidor notifica al cliente su ocurrencia.
Para esto hay que duplicar la arquitectura, requiriéndose dos interfaces, habrá dos niveles de stubs:
- Cliente (stub+skel) y servidor (stub+skel)
Es necesario proveer en el servidor medios para que los clientes registren sus peticiones de callback.
Descarga dinámica de clases
Permite cambios libres en el servidor, elimina la necesidad de distribuir (resguardos) si los hay y nuevas clases.
Dinámicamente, el cliente descarga todas las clases que necesita para desarrollar una RMI válida, mediante HTTP o FTP.
Novedades a partir de JDK 1.5
Soporta generación dinámica de resguardos, prscinde del generador rmic
s