Vous êtes sur la page 1sur 9

Prctica 7

RMI Y THREADS
1. Introduccin a RMI .................................................................................... 1
1.1. Caractersticas de RMI ...................................................................................................................................1
1.2. Pasos para desarrollar una aplicacin RMI....................................................................................................2
2. Aplicacin RMI paso a paso ....................................................................... 2
2.1. Definicin de la interfaz para comunicarse con el objeto remoto ...................................................................2
2.2. Implementacin de la interfaz remota ............................................................................................................2
2.3. Implementacin del servidor de objetos remotos ...........................................................................................2
2.4. Implementacin del cliente .............................................................................................................................3
2.5. Generacin de Stubs y Skeletons ..................................................................................................................4
3. Ejecucin de una aplicacin RMI ............................................................... 4
3.1. Pasos para la ejecucin de la aplicacin RMI ................................................................................................4
4. Threads....................................................................................................... 5
4.1. Introduccin a Threads...................................................................................................................................5
4.2. Formas de crear threads de ejecucin: ..........................................................................................................5
Ejemplo heredando de thread.............................................................................................................................. 6
Ejemplo implementando la interfaz Runnable ..................................................................................................... 6
4.3. Sincronizacin ................................................................................................................................................6
Acceso a datos compartidos................................................................................................................................ 6
Ejemplo de sincronizacin ................................................................................................................................... 7
5. Ampliacin de la prctica .......................................................................... 8

1. Introduccin a RMI

1.1. Caractersticas de RMI


Uno de los principales objetivos de RMI (Remote Method Invocation) es permitir a los
programadores el desarrollo de aplicaciones distribuidas con Java de una forma sencilla, como
si se estuviera implementando una aplicacin no distribuida. Para lograr esto, se ha
reproducido el modelo de trabajo con clases y objetos para una sola mquina virtual en un
nuevo modelo para varias mquinas virtuales.
A travs de RMI se pueden invocar mtodos de objetos remotos, que se encuentran
ejecutndose en otras mquinas virtuales, como si estuvieran en local.
Caractersticas de RMI:
 Es fcil de utilizar y muy flexible, permitiendo la construccin de aplicaciones
cliente/servidor de una forma rpida y sencilla.
 Las aplicaciones basadas en RMI pueden ser ejecutadas sobre cualquier mquina
virtual.
 RMI permite distribuir comportamiento sobre una red.
 Incluye mecanismos de seguridad a travs del security manager.
 Contiene un garbage collector para liberar la memoria de los objetos remotos.

1 de 1
1.2. Pasos para desarrollar una aplicacin RMI
1. Definir una interfaz con los servicios que ofrece el objeto remoto. Se define una interfaz
para especificar la forma en que se va a llevar a cabo la comunicacin entre
componentes. La interfaz definir los mtodos que se podrn invocar de forma remota.
2. Construir una clase que implementa la interfaz definida en el paso 1.
3. Escribir la aplicacin servidora que se encargar de instanciar y registrar los objetos que
se invocarn de forma remota.
4. Construir el cliente que debe localizar y utilizar el objeto remoto.
5. Compilar las clases con el compilador de java (javac).
6. Ejecutar el compilador de RMI (rmic) para generar las clases de soporte (stubs y
skeletons).

2. Aplicacin RMI paso a paso

2.1. Definicin de la interfaz para comunicarse con el objeto remoto


En este primer paso se define la interfaz que describir los mtodos del objeto remoto. Para
que esta sea una interfaz remota, tiene que extender la interfaz java.rmi.Remote y todos los
mtodos que la componen deben lanzar excepciones de tipo java.rmi.RemoteException.
// Interfaz remota
import java.rmi.*;
public interface Eco extends Remote
{
public String mensaje(String nombre) throws RemoteException;
}

2.2. Implementacin de la interfaz remota


En este segundo paso se implementa la interfaz definida anteriormente a travs de una clase
que ser de la cul se instancien realmente los objetos remotos. Esta clase debe tener como
requisitos, adems de implementar la interfaz remota, heredar de la clase
java.rmi.server.UnicastRemoteObject. Tambin se debe proporcionar como mnimo un
constructor sin parmetros para la clase. En nuestro ejemplo esta clase la llamaramos
EcoImpl, es decir la clase que implementa la interfaz Eco.
import java.rmi.*;
import java.rmi.server.*;

public class EcoImpl extends UnicastRemoteObject implements Eco


{
// Implementacin del mtodo remoto
public String mensaje(String nombre)
{
return "\nHola " + nombre +"!!";
}

// Constructor sin parmetros. Este constructor debe lanzar una


// RemoteException, puesto que el constructor de la superclase
// UnicastRemoteObject, lanza esa misma excepcion.
public EcoImpl() throws RemoteException { }
}

2.3. Implementacin del servidor de objetos remotos


En una aplicacin RMI, es necesario contar con una aplicacin que se encargue de instanciar
los objetos remotos y publicarlos para que puedan ser utilizados desde otras aplicaciones.
Esta es la funcionalidad que se debe implementar en la clase servidora de objetos remotos, la
cual se encargar de instanciarlos, registrarlos y mantenerlos activos. Realmente, servidores

2 de 2
ms avanzados deben ser capaces de instanciar objetos remotos bajo demanda y
mantenerlos o destruirlos segn su tiempo de utilizacin.
Nuestro servidor se llamar EcoServer, y es muy sencillo. Se encargar de crear un objeto de
la clase que implementa la interfaz remota, luego registra este objeto en un servidor de
nombres (que en el caso de Java ser el rmiregistry). A travs de este servidor de nombres los
clientes conocern el nombre con el cual se encuentra publicado el objeto remoto y lo
utilizarn para obtener referencias al mismo y ejecutar sus mtodos.

import java.rmi.*;

class EcoServer
{
public static
static void main(String args[]) throws Exception
{
EcoImpl ref = new EcoImpl();
// Registrar el objeto remoto en el servidor de nombres,
// asocindolo a un nombre que ser utilizado desde el cliente
Naming.rebind("Eco", ref);

// El mtodo rebind crea un thread que mantiene vivo el //objeto


System.out
out.println("Servidor
out en ejecucin y objeto registrado");
}
}

2.4. Implementacin del cliente


En la aplicacin cliente se utilizar el mismo identificador con que fue registrado el objeto
remoto para localizarlo en el servidor de nombres y obtener la referencia que permita llamar a
sus mtodos. En el cliente es necesario disponer de la interfaz a partir de la cual se
implement el objeto remoto, para poder as comunicarse con l. Es decir, en nuestro ejemplo
se necesita la interfaz Eco para compilar la clase EcoClient que representar al cliente.

// En este ejemplo se deben pasar por la lnea de comandos


// el nombre del servidor del objeto remoto y la cadena que se le va
// a pasar al mtodo remoto como argumento

import java.rmi.*;

public class EcoClient


{
public static void main (String args[]) throws Exception
{
if (args.length != 2)
{
System.out
out.println(
out "Error, se debe pasar Servidor " +
" y Mensaje para el mtodo");
System.exit(1);
}
// Se construye la url que indica el sitio donde se
// encuentra ejecutndose el servicio de nombres (args[0])
// y cul es el objeto del cual se quiere obtener una
// referencia
String url = "rmi://" + args[0] + "/Eco";

// El mtodo lookup busca en el servicio de nombres una


// url que se corresponda, y devuelve una referencia al
// objeto remoto de tipo Object. Para utilizarla, es
// necesario hacer casting a la interfaz remota, que debe
// ser conocida por el cliente
Eco ref = (Eco) Naming.lookup(url);
//Invocacin del mtodo remoto
String m = ref.mensaje(args[1]);
System.out
out.println(m);
out
}
}

3 de 3
2.5. Generacin de Stubs y Skeletons
Es necesario para la ejecucin generar un stub y un skeleton para la clase que implementa la
interfaz remota. El stub generado jugar el papel de proxy en el cliente, de manera que ste se
comunicar con el stub como si estuviera comunicndose con el objeto en local. Ser el stub
el encargado de enviar las peticiones de invocacin de mtodos y parmetros y luego de
devolver el valor de retorno al cliente. El stub no se comunica directamente con el servidor
remoto, sino con un skeleton que es el que lee los parmetros del mtodo y se encarga de
invocarlo, y enviar el valor de retorno del mismo de regreso al stub.
Para generar el stub y el skeleton de la clase que implementa la interfaz remota (EcoImpl) se
utiliza el compilador de RMI rmic. Lo que se le pasa como argumento es el fichero con
extensin .class. La sintaxis es:

rmic vcompat EcoImpl

Utilizamos la opcin vcompat para que se generen un stub y un skeleton compatibles con la
versin 1.1 y 1.2, ya que la opcin por defecto slo generara el stub. Esto provocar que se
generen, adems de los .class que ya existan, el stub y el skeleton, es decir:
Eco.class
EcoImpl.class
EcoImpl_Skel.class
EcoImpl_Stub.class
EcoServer.class
EcoClient.class

3. Ejecucin de una aplicacin RMI

3.1. Pasos para la ejecucin de la aplicacin RMI


1. Ejecutar el servicio de registro y bsqueda de nombres en la mquina del servidor:
rmiregistry. El rmiregistry permite registrar y localizar objetos remotos utilizando nombres
sencillos. Un servidor puede tener integrado su propio servicio de registro de nombres o
puede compartir uno que d servicio a toda una red.
La aplicacin del lado del servidor utilizar este servicio para registrar los nombres que los
clientes utilizarn para localizar los objetos remotos. Este servicio se debe mantener activo
escuchando por un puerto las peticiones que realizan los clientes, por lo que hay que
ejecutarlo en background.
El comando para ejecutarlo es rmiregistry y no produce ninguna salida por consola.
Dependiendo de si se ejecuta en Windows o Linux, la sintaxis es:

Windows:
start rmiregistry
Linux:
rmiregistry &

2. El siguiente paso es la ejecucin del servidor de objetos remotos, responsable de


instanciar un objeto de la clase que implementa la interfaz remota y de registrarlo en el
servicio de nombres. Esta ejecucin es recomendable realizarla en otra consola. La
sintaxis utilizando nuestro ejemplo es:

4 de 4
java EcoServer

Servidor de Objetos

3. Luego ya es posible ejecutar el cliente, ya sea en la misma mquina o en una mquina


conectada a travs de la red. Se debe poner en el CLASSPATH la ruta de los .class
generados. Si se va a ejecutar el cliente en la misma mquina, abrir otra consola y
ejecutar:

java EcoClient localhost Andres

App Cliente Servidor Parmetro

Si se va a ejecutar el cliente en otra mquina, es necesario tener en la misma, adems de


la aplicacin cliente (EcoClient.class), la interfaz remota (Eco.class) y el stub
(EcoImpl_Stub.class) y asegurarse de poner la ruta de stos en el CLASSPATH de la
mquina cliente. La ejecucin entonces sera:

java EcoClient ServidorRemoto Andres

La salida de esta aplicacin sera el siguiente mensaje en la consola del cliente:


Hola Andres!!

4. Threads

4.1. Introduccin a Threads


Actualmente la mayora de los sistemas operativos (como Linux y Windows en sus ltimas
versiones) permiten ejecutar ms de un proceso a la vez. Esto tambin se refleja en los
lenguajes de programacin, a travs de la programacin concurrente, como la posibilidad de
realizar ms de una tarea al mismo tiempo y en un mismo programa.
Un proceso es un programa en ejecucin que est formado por uno o ms hilos (threads) de
ejecucin concurrente. Un thread es una parte de un proceso que ejecuta un conjunto de
instrucciones. Todos los threads de un proceso pueden compartir los recursos (memoria,
ficheros abiertos, canales de comunicacin, etc.) que el proceso pone a su disposicin. Hasta
ahora hemos realizado programas que trabajan con un solo hilo. Con varios hilos se puede
realizar varias tareas de forma simultnea en el mismo proceso.
La clase Thread del paquete java.lang permite crear y controlar los hilos. Un hilo o contexto de
ejecucin est compuesto de tres partes principales: una CPU, cdigo y datos. Se dice que un
hilo tiene su propia CPU, en realidad tiene una CPU virtual, pues tiene sus propios registros,
pila, contador de programa, etc.

4.2. Formas de crear threads de ejecucin:


Existen dos formas de trabajar con Hilos en Java. Una heredando de la clase Thread y otra
implementando la interfaz Runnable.

5 de 5
Ejemplo heredando de thread
La primera forma (heredar de la clase Thread) se muestra a continuacin:

public class MiHilo extends Thread


{
public void run()
{
while(true
while true)
true
{
System.out
out.println("Hilo
out activo");
}
}

public static void main(String args[])


{
MiHilo h=new
new MiHilo();
h.start();
while(true
while true)
true
{
System.out
out.println("main
out activo");
}
}
}

Ejemplo implementando la interfaz Runnable


La otra forma de trabajar con hilos es implementar la interfaz Runnable, cuyo nico mtodo es
run, que es el que se ejecuta cuando iniciamos el hilo. La ventaja que tiene esta forma, es que
me permite heredar de otra clase. Por ejemplo:

public class MiHilo implements Runnable


{
public void run()
{
while(true
while true)
true
{
System.out
out.println("Hilo
out activo");
}
}

public static void main(String args[])


{
MiHilo h = new MiHilo();
Thread t = new Thread(h);
t.start();
while(true
while true)
true
{
System.out
out.println("main
out activo");
}
}
}

4.3. Sincronizacin
Acceso a datos compartidos
Cuando varios hilos acceden a los mismos datos, es decir, tienen datos compartidos, podemos
tener problemas. Por ejemplo, si tengo una pila y dos hilos accediendo a ella, puede haber
inconsistencia con los datos.
Este problema se resuelve en java con el modificador synchronized aplicndolo a cada
mtodo (push y pop). De esta forma se garantiza que hasta que no se termine de ejecutar el
mtodo sincronizado, no se le da el control a otro hilo. Para esto se chequea un flag de
bloqueo que se activa cuando se entra en un mtodo sincronizado y slo se libera si el mtodo
ha terminado.

6 de 6
En java cada objeto tiene asociado un flag de bloqueo. La palabra clave synchronized
permite la interaccin con este flag, garantizando el acceso exclusivo al cdigo que afecta a
los datos compartidos.
Todos los accesos a datos compartidos deben estar sincronizados. Los datos protegidos por
synchronized deben ser privados.
Ejemplo de sincronizacin
A continuacin mostramos un ejemplo de dos hilos que acceden a un objeto de la clase Pila.
Un hilo se encarga de llamar al mtodo push (HiloInsertar) y otro llama al mtodo pop
(HiloExtraer). Como ambos utilizan la mima pila, es necesario crear una clase Pila con sus
mtodos push y pop sincronizados.

import java.lang.*;

class Pila
{
private char [] datos = new char [10];
private int cima = 0;

synchronized public void push(char


char c)
{
datos[cima] = c;
System.out
out.println("El
out caracter insertado es:" + c);
cima++;
}
synchronized public char pop()
{
cima--;
System.out
out.println("El
out caracter extraido es:" + datos[cima]);
return datos[cima];
}
}

class HiloExtraer extends Thread


{
private Pila p;
public HiloExtraer(Pila p1)
{
p=p1;
}

public void run()


{
while(true
while true)
true
{
char c = p.pop();
try
{
Thread.sleep(1000);
}
catch (InterruptedException e) {}
}
}
}
class HiloInsertar extends Thread
{
private Pila p;
static int i=0;
public HiloInsertar(Pila p1)
{
p = p1;
}
public void run()
{
while(true
while true)
true
{

7 de 7
i++;
if (i>=10) i=1;
p.push(Character.forDigit(i,10));
try
{
Thread.sleep(1000);
}
catch (InterruptedException e) {}
}
}
}
public class PruebaPila
{
public static void main (String args[])
{
Pila p = new Pila();
HiloInsertar h1 = new HiloInsertar(p);
h1.start();
HiloInsertar h2 = new HiloInsertar(p);
h2.start();
HiloInsertar h3 = new HiloInsertar(p);
h3.start();
HiloInsertar h4 = new HiloInsertar(p);
h4.start();
HiloExtraer h5 = new HiloExtraer(p);
h5.start();
HiloExtraer h6 = new HiloExtraer(p);
h6.start();
HiloExtraer h7 = new HiloExtraer(p);
h7.start();
HiloExtraer h8 = new HiloExtraer(p);
h8.start();
}
}

5. Ampliacin de la prctica
Para completar la prctica se debe desarrollar por parte de los alumnos una aplicacin
completa de RMI (servidor y cliente) partiendo de la clase Jugador que mostramos a
continuacin y que representar el tipo del objeto que ser retornado por el mtodo de la
interfaz remota ServicioJugador. Para desarrollar la aplicacin RMI completa, habr que
implementar las clases ServicioJugadorImpl (clase que implementa la interfaz remota),
ServicioJugadorServer (clase servidora de objetos remotos) y ServicioJugadorCliente
(clase cliente del objeto remoto). Para la implementacin y la ejecucin, debe guiarse por los
pasos descritos anteriormente en la prctica.

Clase Jugador
// Clase que define los datos de tipo jugador
// tiene que ser serializable pues sus objetos
// sern retornados por un mtodo remoto
import java.io.*;
public class Jugador implements
implements Serializable{
String nombre;
String apellido;
private Integer edad;
public Jugador(String nom, String ape, Integer edad)
{
nombre = nom;
apellido = ape;
this.edad
this = edad;
}

public void setEdad(Integer edad)


{

8 de 8
this.edad
this = edad;
}

public Integer getEdad()


{
return(edad);
return
}
}

Interfaz Remota: ServicioJugador


public interface ServicioJugador extends java.rmi.Remote
{
// Mtodo que devuelve un objeto de la clase Jugador
public Jugador getJugador(String nombre)
throws java.rmi.RemoteException;
}

9 de 9

Vous aimerez peut-être aussi