Ejemplo de Java Remote Method Invocation | RMI

Introducción

Ya vimos en un ejercicio anterior cómo conectar un socket cliente y uno servidor para mandar mensajes.

Enviar mensajes no tiene gran utilidad, ¿no sería mejor poder llamar a algunas funciones en el servidor? esto es justamente lo que hace RMI en Java. Declaramos el servidor, el cliente, y la interfaz que servirá como “pegamento” entre estos dos y que se encargará del paso de parámetros.

Después, desde el cliente llamamos a las funciones declaradas anteriormente.

De esta manera, todos los métodos se ejecutarán en el servidor. En este caso haremos una calculadora, para no hacer el post muy largo, pero podemos hacer miles de cosas; se me ocurre, por ejemplo, conectar a una base de datos.

En fin, vamos allá.

Ejemplo de RMI

Interfaz remota

Comencemos con la interfaz remota, como lo dije hace un momento esta servirá como pegamento. Veamos una cosa interesante, como se puede ver dice “public interface” en lugar de “public class“.

Esto es porque, aunque suene redundante, es una interfaz y recordemos que éstas sólo sirven para ser sobrescritas más tarde. ¿Y en dónde las sobrescribiremos? en el código del servidor.

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

/*
	Declarar firma de métodos que serán sobrescritos
*/
public interface Interfaz extends Remote {
    float sumar(float numero1, float numero2) throws RemoteException;
    float restar(float numero1, float numero2) throws RemoteException;
    float multiplicar(float numero1, float numero2) throws RemoteException;
    float dividir(float numero1, float numero2) throws RemoteException;
}

En este caso, como haremos una calculadora sólo declaramos la firma de 4 métodos: sumar, restar, multiplicar, y dividir.

Todos reciben dos parámetros flotantes, y todos devuelven un dato del mismo tipo.

Además, indicamos que el método puede lanzar una excepción de tipo RemoteException.

Servidor

Ahora veamos el servidor. Este se encarga de exportar el objeto, sobrescribir funciones de la interfaz y escuchar peticiones del cliente.

import java.rmi.AlreadyBoundException;
import java.rmi.Remote;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import java.rmi.server.UnicastRemoteObject;
public class Servidor {
	private static final int PUERTO = 1100; //Si cambias aquí el puerto, recuerda cambiarlo en el cliente
    public static void main(String[] args) throws RemoteException, AlreadyBoundException {
        Remote remote = UnicastRemoteObject.exportObject(new Interfaz() {
        	/*
				Sobrescribir opcionalmente los métodos que escribimos en la interfaz
        	*/
            @Override
            public float sumar(float numero1, float numero2) throws RemoteException {
                return numero1 + numero2;
            };

            @Override
            public float restar(float numero1, float numero2) throws RemoteException {
                return numero1 - numero2;
            };

            @Override
            public float multiplicar(float numero1, float numero2) throws RemoteException {
                return numero1 * numero2;
            };

            @Override
            public float dividir(float numero1, float numero2) throws RemoteException {
                return numero1 / numero2;
            };
        }, 0);
        Registry registry = LocateRegistry.createRegistry(PUERTO);
       	System.out.println("Servidor escuchando en el puerto " + String.valueOf(PUERTO));
        registry.bind("Calculadora", remote); // Registrar calculadora
    }
}

Como observamos, ya hemos sobrescrito los métodos con el cuerpo real de la función. La anotación @Override no es necesaria, pero es una buena práctica indicar que estamos sobrescribiendo una función.

Finalmente escuchamos en localhost (cosa que no podemos cambiar) en el puerto definido en la constante PUERTO.

Cliente

Para terminar con el código veamos ahora el cliente:

import java.rmi.NotBoundException;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import java.util.Scanner;
public class Cliente {
	private static final String IP = "192.168.1.15"; // Puedes cambiar a localhost
	private static final int PUERTO = 1100; //Si cambias aquí el puerto, recuerda cambiarlo en el servidor
	
    public static void main(String[] args) throws RemoteException, NotBoundException {
        Registry registry = LocateRegistry.getRegistry(IP, PUERTO);
        Interfaz interfaz = (Interfaz) registry.lookup("Calculadora"); //Buscar en el registro...
        Scanner sc = new Scanner(System.in);
        int eleccion;
        float numero1, numero2, resultado = 0;
        String menu = "\n\n------------------\n\n[-1] => Salir\n[0] => Sumar\n[1] => Restar\n[2] => Multiplicar\n[3] => Dividir\nElige: ";
        do {
            System.out.println(menu);

            try {
                eleccion = Integer.parseInt(sc.nextLine());
            } catch (NumberFormatException e) {
                eleccion = -1;
            }

            if(eleccion != -1){

            	System.out.println("Ingresa el número 1: ");
            	try{
                	numero1 = Float.parseFloat(sc.nextLine());
            	}catch(NumberFormatException e){
            		numero1 = 0;
            	}

            	System.out.println("Ingresa el número 2: ");
            	try{
                	numero2 = Float.parseFloat(sc.nextLine());
            	}catch(NumberFormatException e){
            		numero2 = 0;
            	}
                switch (eleccion) {
	                case 0:
	                    resultado = interfaz.sumar(numero1, numero2);
	                    break;
	                case 1:
	                    resultado = interfaz.restar(numero1, numero2);
	                    break;
	                case 2:
	                    resultado = interfaz.multiplicar(numero1, numero2);
	                    break;
	                case 3:
	                    resultado = interfaz.dividir(numero1, numero2);
	                    break;
	            }

                System.out.println("Resultado => " + String.valueOf(resultado));
                System.out.println("Presiona ENTER para continuar");
                sc.nextLine();
            }
        } while (eleccion != -1);
    }
}

En el cliente imprimimos un menú, y dejamos que el usuario elija. Los try/catch son por si existe algún número mal formado, o por si dejan la cadena vacía, etcétera.

Como vemos, podemos llamar a los métodos remotos como si se trataran de métodos locales, simplemente usando a la interfaz.

Ejecución

El código no sirve para nada si no lo compilamos y probamos. Recuerda que puedes compilarlo desde un IDE, o desde la terminal como los macho alfa.

En fin, compilemos los 3 archivos…

Ahora ejecutaré el servidor en una terminal:

Y el cliente en otra:

Nota: no sé por qué los acentos no se muestran correctamente, pero igual y no es una cosa que afecte al programa, sólo es molesto a la vista. Si lo deseas, simplemente cambia la ú por u. O ejecuta el programa desde un IDE.

Conclusión

La ventaja de esto es que todo el proceso se hace en el servidor, y si tenemos uno muy robusto pues qué mejor que dejar que él haga todas las operaciones que se llevarían más tiempo si las hiciéramos en una computadora normal.

Recuerda que en este ejemplo, la ip es la de mi pc. Si vas a conectar a otra computadora en una red, simplemente escribe su ip.

Lo mismo aplica para el puerto, si quieres escuchar en otro número recuerda cambiarlo tanto en el cliente como en el servidor.

Creo que poco a poco Java me va cayendo mejor.

Estoy aquí para ayudarte 🤝💻


Estoy aquí para ayudarte en todo lo que necesites. Si requieres alguna modificación en lo presentado en este post, deseas asistencia con tu tarea, proyecto o precisas desarrollar un software a medida, no dudes en contactarme. Estoy comprometido a brindarte el apoyo necesario para que logres tus objetivos. Mi correo es parzibyte(arroba)gmail.com, estoy como@parzibyte en Telegram o en mi página de contacto

No te pierdas ninguno de mis posts 🚀🔔

Suscríbete a mi canal de Telegram para recibir una notificación cuando escriba un nuevo tutorial de programación.

2 comentarios en “Ejemplo de Java Remote Method Invocation | RMI”

Dejar un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *