Descargar - Departament d`Informàtica

Anuncio
Llamada a métodos remotos (RMI).
Curso 04/05
LP (Telemática)
Universitat de València
Tema 9
Llamada a métodos remotos (RMI).
Departament d’Informàtica. Universitat de València
Índice
1. Introducción
2
1.1. ¿Cómo funciona RMI? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
2. Usando RMI
2
4
2.1. Fase de desarrollo: el servidor . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
4
2.1.1. Creación de una interface que describe el servicio . . . . . . . . . . . . . . . . . . . . . . .
4
2.1.2. Implementación de la interface . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
5
2.1.3. Generación de stub (SDK 1.2) o stub y skeleton (SDK 1.1) . . . . . . . . . . . . . . . . .
6
2.1.4. Clase que crea una instancia del servicio y la registra . . . . . . . . . . . . . . . . . . . . .
6
2.2. Fase de ejecución: el servidor . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
7
2.2.1. Iniciar rmiregistry . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
7
2.2.2. Iniciar el servidor . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
7
2.3. Fase de desarrollo: el cliente . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
8
2.3.1. Creación del cliente . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
8
2.4. Fase de ejecución: el cliente . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
9
2.4.1. Iniciar el cliente
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
2.5. Una situación realista: carga dinámica clases
[email protected]
. . . . . . . . . . . . . . . . . . . . . . . . . . . . .
9
9
Página: 1
Llamada a métodos remotos (RMI).
Curso 04/05
1.
LP (Telemática)
Universitat de València
Introducción
¿Qué es RMI (Remote Method Invocation)? Es una tecnologı́a Java que permite enviar mensajes a
objetos situados en otra máquina virtual desde una aplicación que esté ejecutándose en una máquina
virtual.
En su versión básica requiere que toda la aplicación (tanto el cliente como el servidor) estén
desarrollados en Java.
Máquina Virtual
Máquina Virtual
metodo1()
Cliente RMI
.
Servidor RMI
n
Respuesta
Objeto remoto
metodo1()
Esto permite tener los objetos distribuidos en diversas máquinas.
Esta tecnologı́a permite que se puedan pasar argumentos al método remoto y recibir los datos que
devuelve (en ambos casos pueden ser tipos primitivos u objetos de clases que sean serializables).
Cada servicio RMI (objeto remoto) se define mediante una interface, que fija los métodos que se
pueden invocar en el objeto remoto.
Esta interface debe estar disponible en el cliente y en el servidor.
La tecnologı́a RMI no es un concepto nuevo. Antes de la programación orientada a objetos existı́a
tecnologı́a que permitı́a realizar llamadas a funciones y procedimientos remotos (RPC, Remote Procedure Calls).
En sistemas orientados a objetos también se puede utilizar CORBA (Common Object Request Broker Arquitecture o Arquitectura Común de Agente de Solicitud de Objetos) que soportan la utilización
de diferentes lenguajes.
Java soporta RMI sobre IIOP (Internet Inter-ORB) con lo cual es posible integrar RMI con CORBA.
1.1.
¿Cómo funciona RMI?
Los sistemas que utilizan RMI se dividen en dos categorı́as: clientes y servidores.
El servidor proporciona un servicio RMI y el cliente llama a métodos del objeto ofrecido por el
servicio.
[email protected]
Página: 2
Llamada a métodos remotos (RMI).
Curso 04/05
LP (Telemática)
Universitat de València
El servicio RMI se debe registrar en un servicio de consulta para permitir a los clientes encontrar
el servicio.
El J2SE incluye una aplicación llamada rmiregistry, que lanza un proceso que permite registrar
servicios RMI mediante un nombre. Este nombre identifica al servicio, esto se hace ası́ ya que en una
máquina puede haber diferentes servicios.
Una vez que el servicio se ha registrado, el servidor esperará a que lleguen peticiones RMI desde
los clientes.
El cliente solicita el servicio mediante el nombre con el que fue registrado y obtiene una referencia
al objeto remoto.
El formato utilizado por RMI para representar una referencia al objeto remoto es el siguiente
rmi://hostname:puerto/nombreServicio
Una vez obtenida la referencia remota (ya sea mediante rmiregistry, leyendo el URL de un archivo,...)
los clientes pueden enviar mensajes como si se tratase de objetos ejecutándose en la misma máquina
virtual.
Los detalles de red de las peticiones y las repuestas son transparentes para el desarrollador. Esto
se consigue mediante el uso de stub (a partir de la versión 1.2, ya que en la versión 1.1 se requerı́a
generar un skeleton).
Las capas de la arquitectura RMI son las siguientes:
Capa de stub y skeletons
La capa de stub y skeletons se sitúa bajo la aplicación. En esta capa, RMI utiliza el patrón de
diseño Proxy. En el patrón Proxy, un objeto en un contexto es representado por otro (el proxy) en un
contexto separado.
En el uso que se hace en RMI del patrón proxy, la clase stub realiza el papel del proxy de la
implementación del servicio remoto.
Mediante la utilización de este patrón es posible acceder al servicio como si se tratase de objetos
locales.
[email protected]
Página: 3
Llamada a métodos remotos (RMI).
Curso 04/05
LP (Telemática)
Universitat de València
Antes de que el stub pase una petición al servicio remoto debe agrupar los parámetros (ya sean
tipos primitivos, objetos o ambos) para la transmisión, operación conocida como marshalling.
La clase skeleton es una clase generada por RMI. Esta clase es la responsable de comunicarse con el
stub durante la comunicación RMI. Debe reconstruir los parámetros para formar los tipos primitivos
y objetos, lo que es conocido como unmarshalling.
A partir de la versión 1.2 del SDK, el nuevo protocolo utilizado para RMI no necesita la clase
skeleton.
Capa de Referencia Remota
Esta capa es utilizada por la capa de stub y skeleton. Es la capa responsable del funcionamiento
independientemente de la la capa de transporte que se esté utilizando.
Esta capa proporciona un objeto RemoteRef que representa la conexión con el objeto remoto.
El objeto stub utiliza el método invoke(·) de RemoteRef para enviar las llamadas a los métodos del
objeto remoto.
Capa de Transporte
La capa de transporte realiza la conexión entre las máquinas virtuales. Todas las conexiones son
conexiones de red basadas en flujos que utilizan TCP/IP.
Sobre TCP/IP, RMI utiliza un protocolo llamado Java Remote Method Protocol (JRMP).
Sun e IBM han trabajado de forma conjunta para obtener la nueva versión de RMI llamada RMIIIOP, en la que se puede trabajar con el protocolo IIOP en lugar de JRMP para comunicar clientes y
servidores.
2.
Usando RMI
2.1.
2.1.1.
Fase de desarrollo: el servidor
Creación de una interface que describe el servicio
En este ejemplo, el objeto remoto va a ofrecer un único método getMensaje() que devuelve un String.
La interface que describe el servicio es la siguiente (debe extender a la interface Remote).
[email protected]
Página: 4
Llamada a métodos remotos (RMI).
Curso 04/05
LP (Telemática)
Universitat de València
i m p o r t j a v a . rmi . ∗ ;
/∗ ∗ I n t e r f a c e que d e s c r i b e e l s e r v i c i o RMI
∗ D e f i n e l o s métodos que s e pueden l l a m a r d e s d e e l c l i e n t e
∗/
p u b l i c i n t e r f a c e Saludo e x t e n d s Remote {
/∗ ∗ Metodo que s e d e b e implementar
∗ @return una S t r i n g
∗ @throws RemoteException
∗/
p u b l i c S t r i n g g e t M e n s a j e ( ) t h r o w s RemoteException ;
}
Compilamos:
j a v a c Saludo . j a v a
2.1.2.
Implementación de la interface
El siguiente paso a realizar es crear una clase que implemente a la interface anterior.
Esta clase puede extender a una de las siguientes clases:
UnicastRemoteObject si el objeto va a estar ejecutándose en la máquina virtual remota.
Activatable si el objeto se cargará en la máquina virtual remota cuando algún cliente envı́e un
mensaje.
En el ejemplo mostrado optamos por la primera opción.
Esta clase puede tener otros métodos aparte de los especificados en la interface pero no podrán ser
llamados por el cliente.
i m p o r t j a v a . rmi . s e r v e r . ∗ ;
i m p o r t j a v a . rmi . ∗ ;
/∗ ∗ C l a s e que implementa a l a i n t e r f a c e que d e s c r i b e e l s e r v i c i o
∗/
p u b l i c c l a s s SaludoImpl e x t e n d s UnicastRemoteObject
i m p l e m e n t s Saludo {
p r i v a t e S t r i n g cadena ;
p u b l i c SaludoImpl ( ) t h r o w s RemoteException {
cadena = ” Mensaje d e s d e e l s e r v i d o r RMI” ;
}
/∗ ∗ Metodo d e f i n i d o en l a i n t e r f a c e S a l u d o ∗/
p u b l i c S t r i n g g e t M e n s a j e ( ) t h r o w s RemoteException {
r e t u r n cadena ;
}
}
[email protected]
Página: 5
Llamada a métodos remotos (RMI).
Curso 04/05
LP (Telemática)
Universitat de València
Compilamos:
j a v a c SaludoImpl . j a v a
2.1.3.
Generación de stub (SDK 1.2) o stub y skeleton (SDK 1.1)
Si tanto el servidor como los servidores son Java, podemos trabajar con RMI sobre el protocolo
JRMP.
Si vamos a trabajar con el SDK 1.2 podemos hacer lo siguiente:
rmic −v1 . 2 SaludoImpl
Esto genera la clase SaludoImpl Stub.class
Si vamos a trabajar con el SDK 1.1 (quizá por compatibilidad con software existente) realizamos
lo siguiente:
rmic −v1 . 1 SaludoImpl
Lo cual genera las clases SaludoImpl Stub.class (para el cliente) y la clase SaludoImpl Skeleton.class
(para el servidor).
2.1.4.
Clase que crea una instancia del servicio y la registra
Vamos a crear ahora el servidor RMI.
import
import
import
import
j a v a . n e t . MalformedURLException ;
j a v a . rmi . Naming ;
j a v a . rmi . RMISecurityManager ;
j a v a . rmi . RemoteException ;
/∗ ∗
∗ S e r v i d o r RMI
∗/
public c l a s s SaludoServidor {
p u b l i c s t a t i c v o i d main ( S t r i n g [ ] a r g s ) {
// I n s t a l a m o s un RMISecurityManager ( )
System . s e t S e c u r i t y M a n a g e r ( new RMISecurityManager ( ) ) ;
try {
// Creamos e l o b j e t o que o f r e c e m o s como s e r v i c i o
Saludo s a l = new SaludoImpl ( ) ;
// . . . y l o r e g i s t r a m o s
// Puesto que no estamos e s p e c i f i c a n d o e l h o s t n i e l p u e r t o
// t e n d r á n l o s v a l o r e s por d e f e c t o : / / l o c a l h o s t y 1 0 9 9
Naming . r e b i n d ( ” Saludo ” , s a l ) ;
[email protected]
Página: 6
Llamada a métodos remotos (RMI).
Curso 04/05
LP (Telemática)
Universitat de València
} c a t c h ( RemoteException e ) {
e . printStackTrace () ;
} c a t c h ( MalformedURLException e ) {
e . printStackTrace () ;
}
}
}
2.2.
2.2.1.
Fase de ejecución: el servidor
Iniciar rmiregistry
rmiregistry es una utilidad ofrecida por Sun para registrar los servicios RMI.
rmiregistry crea e inicia un registro de objetos remotos en un determinado puerto de la máquina
local. Si se omite el puerto, el registro se inicia en el puerto 1099.
Un registro de objetos remotos es un servicio de nombres que es utilizado por los servidores RMI de
la máquina para asociar objetos remotos con nombres. Los clientes en la máquina local o en máquinas
remotas pueden buscar objetos remotos a través del nombre con el que se ha registrado el servicio.
Desde el directorio en el que se encuentran todas las clases se lanza el registro:
rmiregistry
2.2.2.
Iniciar el servidor
Puesto que se ha instalado un gestor de seguridad RMI hemos de crear un archivo en el que se
especifiquen lo permisos otorgados a la aplicación (en este caso serán permisos de conexión para los
sockets). El archivo servidor.policy contiene lo siguiente:
grant {
p e r m i s s i o n java . net . SocketPermission ”∗:1024 −65535” , ” connect , accept ” ;
p e r m i s s i o n java . net . SocketPermission ” ∗ : 8 0 ” , ” connect , accept ” ;
};
Desde el directorio donde se encuentran las clases compiladas lanzamos el servidor:
java
−Djava . s e c u r i t y . p o l i c y=s e r v i d o r . p o l i c y S a l u d o S e r v i d o r
[email protected]
Página: 7
Llamada a métodos remotos (RMI).
Curso 04/05
2.3.
2.3.1.
LP (Telemática)
Universitat de València
Fase de desarrollo: el cliente
Creación del cliente
El cliente del servicio RMI será:
import
import
import
import
import
j a v a . n e t . MalformedURLException ;
j a v a . rmi . Naming ;
j a v a . rmi . NotBoundException ;
j a v a . rmi . RMISecurityManager ;
j a v a . rmi . RemoteException ;
/∗ ∗
∗ C l i e n t e RMI
∗/
public c l a s s SaludoCliente {
p u b l i c s t a t i c v o i d main ( S t r i n g [ ] a r g s ) {
// El argumento s e r á e l h o s t donde e s t á e l s e r v i c i o
S t r i n g u r l = ” // l o c a l h o s t / ” ;
System . s e t S e c u r i t y M a n a g e r ( new RMISecurityManager ( ) ) ;
try {
// Obtencion de l o s s e r v i c i o s RMI d i s p o n i b l e s
String [ ]
s e r v i c i o s = Naming . l i s t ( u r l ) ;
// Se muestran l o s s e r v i c i o s RMI
f o r ( i n t i =0; i <s e r v i c i o s . l e n g t h ; i ++)
System . out . p r i n t l n ( s e r v i c i o s [ i ] ) ;
// Obtenemos l a r e f e r e n c i a a l o b j e t o remoto
Saludo s a l = ( Saludo ) Naming . l o o k u p ( u r l + ” Saludo ” ) ;
// Ahora l a u t i l i z a m o s como s i s e t r a t a s e de un o b j e t o
// l o c a l
S t r i n g mensaje = s a l . g e t M e n s a j e ( ) ;
System . out . p r i n t l n ( mensaje ) ;
} c a t c h ( MalformedURLException e ) {
e . printStackTrace () ;
} c a t c h ( RemoteException e ) {
e . printStackTrace () ;
} c a t c h ( NotBoundException e ) {
e . printStackTrace () ;
}
}
}
En el cliente deben estar visibles (en el mismo directorio o en el classpath) la interface que describe
el servicio remoto y la clase stub generada con rmic.
[email protected]
Página: 8
Llamada a métodos remotos (RMI).
Curso 04/05
2.4.
LP (Telemática)
Universitat de València
Fase de ejecución: el cliente
2.4.1.
Iniciar el cliente
Igual que en el caso anterior hemos de dar permisos a los sockets. El archivo cliente.policy
contiene lo siguiente:
grant {
p e r m i s s i o n java . net . SocketPermission ”∗:1024 −65535” , ” connect , accept ” ;
p e r m i s s i o n java . net . SocketPermission ” ∗ : 8 0 ” , ” connect , accept ” ;
};
Desde el directorio donde se encuentran las clases compiladas lanzamos el cliente:
j a v a −Djava . s e c u r i t y . p o l i c y=c l i e n t e . p o l i c y S a l u d o C l i e n t e
2.5.
Una situación realista: carga dinámica clases
En la mayorı́a de situaciones reales, el servidor y el cliente no están en la misma máquina.
En este caso voy a suponer que en la máquina
que va a actuar de servidor RMI se encuentra el directorio Servidor con los siguientes
ficheros:
Servidor
SaludoServidor.class
Saludo.class
SaludoImpl.class
SaludoImpl Stub.class
servidor.policy
Y en la máquina que va a actuar como cliente se encuentra el directorio Cliente con los
siguientes ficheros:
Cliente
SaludoCliente.class
Saludo.class
cliente.policy
En ésta situación ¿cómo puede acceder el cliente a la clase SaludoImpl Stub.class?
La solución es que las clases necesarias se carguen de forma dinámica utilizando la capacidad que
ofrece Java para descargar clases desde un URL.
Esto se puede conseguir utilizando un codebase que es una localización desde la cual la máquina
virtual puede obtener las clases que necesite.
Esta localización se puede establecer utilizando la propiedad java.rmi.server.codebase que representa
uno o más URL’s desde donde se pueden descargar los stubs (y otras clases que sean necesarias).
En este caso, el proceso es el siguiente:
[email protected]
Página: 9
Llamada a métodos remotos (RMI).
Curso 04/05
LP (Telemática)
Universitat de València
Se lanza rmiregistry desde un directorio en el que no esté ninguna de las clases del servidor
Se llevan las clases SaludoImpl Stub.class y Saludo.class a un directorio (voy a suponer que
se llama RMI) del servidor, que voy a suponer es un servidor HTTP al que se puede acceder como
http://host
Es decir, que las clases se pueden encontrar en http://host/RMI/
Se lanza el servidor RMI especificando en la propiedad java.rmi.server.codebase el valor
http://host/RMI/. El servidor registra el objeto remoto, asociado a un nombre en el registro.
El registro (rmiregistry) carga las clases Saludo.class y SaludoImpl Stub.class del codebase
especificado por el servidor.
Se lanza el cliente RMI. Solicita una referencia del objeto al registro.
El registro devuelve una refencia (el stub) y si el cliente no encuentra el fichero con la clase
intentará obtenerlo en el codebase especificado.
El cliente pide el fichero con la clase. El codebase que utiliza el cliente es el que quedó asociado
al stub cuando se registró el objeto remoto.
El cliente descarga la clase SaludoImpl Stub.class de http://host/RMI/.
La instrucción que se ha utilizado para ejecutar el servidor es:
j a v a −Djava . s e c u r i t y . p o l i c y=s e r v i d o r . p o l i c y −Djava . rmi . s e r v e r . c o d e b a s e=h t t p : / / h o s t /RMI/
SaludoServidor
Y la que se ha utilizado para ejecutar el cliente es:
j a v a −Djava . s e c u r i t y . p o l i c y=c l i e n t e . p o l i c y
SaludoCliente
Si se desea ver cuales son las llamadas que se están realizando desde el cliente se pueden establecer
las siguientes propiedades al lanzar el servidor:
−Djava . rmi . s e r v e r . l o g C a l l s=t r u e
l o g L e v e l=VERBOSE
−Djava . rmi . s e r v e r . l o g L e v e l=VERBOSE
−Djava . rmi . l o a d e r .
Si no se dispone de un servidor HTTP o FTP se pueden obtener dos clases que se pueden utilizar
como servidor de ficheros en la dirección:
http://java.sun.com/products/jdk/rmi/class-server.zip
Tras descomprimir y compilar las clases que contiene este fichero zip se puede ejecutar indicando
el número de puerto y el directorio donde se encuentran los ficheros con las clases:
java ClassFileServer 8 0 ruta
[email protected]
Página: 10
Llamada a métodos remotos (RMI).
Curso 04/05
LP (Telemática)
Universitat de València
Y ejecutar el servidor del siguiente modo:
j a v a −Djava . s e c u r i t y . p o l i c y=s e r v i d o r . p o l i c y −Djava . rmi . s e r v e r . c o d e b a s e=h t t p : / / l o c a l h o s t /
SaludoServidor
[email protected]
Página: 11
Descargar