Curso Java. Volumen X. Todo sobre RMI en Java (Programación distribuída)

Escrito por Sergio De Luz
Java
0

En anteriores volúmenes vimos cómo se realizan programas concurrentes en Java y las diferencias con un programa secuencial. Los ejemplos de programas concurrentes y la teoría estaban hechos sobre una memoria común (misma memoria RAM de un mismo equipo).

Si queremos conseguir un mayor rendimiento, podemos utilizar varios ordenadores simultáneamente y de esta forma tener más velocidad de cálculo y más memoria para hacer determinados algoritmos. Para lograr esto, necesitamos comunicarnos y sincronizarnos con los demás ordenadores para que el resultado del programa sea correcto.

A continuación, os vamos a enseñar todo sobre RMI.

Lo primero que debemos saber es qué es un RPC. Un RPC, o también conocido como Llamada a Procedimientos Remotos la cual consiste en comunicarse y sincronizarse con otros procesos que están en otro equipo.

Cuando llamamos a un proceso se produce lo siguiente:

  • Se crean los canales de comunicación de forma automática.
  • Se envía la información que hayamos introducido en la llamada.
  • Gestión automática de bloqueos por si hay varias llamadas a un mismo proceso y está ocupado atendiendo anteriores.
  • Recepción de la respuesta y preparación de los parámetros de salida

Cuando un proceso es llamado se produce lo siguiente:

  • Se crean los canales de comunicación de forma automática.
  • Se espera a recibir la información, si no está disponible, bloqueamos el proceso.
  • Si recibimos la llamada, se cargan los parámetros y se ejecuta código.
  • Enviamos la respuesta como resultado de dicha ejecución de código.

La comunicación es síncrona, por lo que los procesos deben “esperarse”. Hay varios tipos de RPC, pero que el usaremos es el RMI (Invocación de métodos remotos en Java).

RMI

Permite pasar objetos por referencia, recolección de basura distribuída y paso de tipos arbitrarios. Cuando un determinado programa exporta un objeto, estarán accesibles a través de la red mediante un servidor de registro (rmiregistry), dicho programa permanece a la espera de peticiones mediante el protocolo TCP (gestionado internamente por RMI, no debemos hacer nada). Una vez que lo hemos exportado, un programa puede usarlo e invocar los métodos que proporciona dicho objeto. La invocación de objetos es totalmente transparente, y se realiza como si dicha invocación hubiera sido de forma local (en la misma máquina).

RMI posee una arquitectura en cuatro capas:

  • Capa de aplicación: se encarga de implementar las aplicaciones cliente-servidor, se realizan llamadas de alto nivel y los métodos se declaran extendiendo java.rmi.Remote
  • Capa proxy: está muy relacionada con la capa de aplicación, se encarga de preparar las llamadas a objetos remotos.
  • Capa de referencia remota: Es la responsable de la semántica de las invocaciones remotas así como gestionar la replicación de los objetos.
  • Capa de transporte: Se encarga de realizar la conexión, se realiza mediante el protocolo JRMP, que sólo entiende Java.

Cualquier programa RMI es cliente-servidor. En el servidor RMI se realiza la creación de objetos remotos, las referencias a ellos para que sean accesibles y se espera a que accedan a ellos. En el cliente RMI invocamos los métodos del servidor y obtenemos una referencia a objetos remotos en el servidor.

Pasos para la creación de un servidor RMI:

  • Lo primero que debemos hacer es definir la interfaz remota la cual debe ser public y heredar de java.rmi.Remote y lanzará java.rmi.RemoteException
  • A continuación debemos hacer una clase que implemente la interfaz remota y que heredará de UnicastRemoteObject. El constructor lanzará UnicastRemoteException.
  • Hacer visible el objeto remoto mediante Naming.rebind()
  • Compilar y ejecutar.

Pasos para la creación de un cliente RMI:

  • Definir una clase para obtener los objetos remotos mediante Naming.lookup()
  • Compilar y ejecutar

Hasta aquí hemos llegado con la teoría, ahora comenzamos la práctica.

Lo primero que debemos hacer es ejecutar correctamente el servidor de registro RMI, para ello debemos editar las variables de entorno de Windows tal y como está en la captura de pantalla.

En el CLASSPATH ponemos C:Javajre7bin y en PATH lo mismo (en ambos).

Ahora deberéis abrir una consola en CMD y ejecutar: rmiregistry para iniciar el servidor de registro, sino, RMI no funcionará y dará error al ejecutar. Una vez que lo hemos ejecutado, nos aparecerá el cursor parpadeando pero sin poner nada.

Ahora vamos a hacer un programa muy sencillo con RMI:

Primero vamos a crear la interfaz, nos fijamos que hereda de Remote y que lanza la excepción RemoteException:


package rmi;

import java.rmi.Remote;
import java.rmi.RemoteException;

public interface InterfaceRMI extends Remote {
String PrimerMetodo () throws RemoteException;
}

Ahora vamos a crear una clase que haga uso de esta interfaz, simplemente lo que hará es devolver una cadena cuando invoquemos el método.


package rmi;

import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;

public class UsarInterfaceRMI extends UnicastRemoteObject implements InterfaceRMI {

public UsarInterfaceRMI() throws RemoteException {
}

@Override
public String PrimerMetodo() throws RemoteException {
return("Hola Primer Método");
}
}

Creamos el servidor RMI:


package rmi;

import java.net.MalformedURLException;
import java.rmi.Naming;
import java.rmi.RemoteException;

public class ServidorRMI {

public static void main(String[] args) throws RemoteException, MalformedURLException {
UsarInterfaceRMI uso = new UsarInterfaceRMI(); //Creamos el objeto uso
Naming.rebind("//127.0.0.1/Objeto", uso);  //Hacemos visible el objeto remoto, mucho cuidado con /Objeto, debe ser igual en el cliente RMI.
System.out.println("El servidor ha arrancado correctamente");
}
}

Por último, creamos el cliente RMI:


package rmi;

import java.net.MalformedURLException;
import java.rmi.Naming;
import java.rmi.NotBoundException;
import java.rmi.RemoteException;

public class ClienteRMI {

public static void main(String[] args) throws NotBoundException, MalformedURLException, RemoteException {
InterfaceRMI inter = (InterfaceRMI) Naming.lookup("//127.0.0.1/Objeto");  //Creamos el objeto remoto mediante la orden, acordaos de poner /Objeto, o si queréis ponéis /loquesea, pero debe ser igual en el servidor y en el cliente
inter.PrimerMetodo(); //Llamamos al método (por si hiciera alguna acción, en este caso devuelve un string por lo que no hará nada aquí).
System.out.println(""+inter.PrimerMetodo()); //Imprimimos el string que hemos "return" en el servidor RMI
}
}

RMI es una herramienta muy potente, el poder ejecutar métodos remotos permite que tengamos un gran rendimiento en nuestras aplicaciones.

Esperamos que os haya servido de ayuda esta teoría y ejemplo con RMI.