JavaRush /Blog Java /Random-ES /RMI: práctica de uso

RMI: práctica de uso

Publicado en el grupo Random-ES
¡Hola! Hoy veremos un tema bastante interesante: RMI . Esto significa Invocación de método remoto . RMI: práctica de uso - 1Con RMI, puede enseñar a dos programas a comunicarse entre sí, incluso si están en computadoras diferentes. ¿Suena bien? :) ¡Pero no es tan difícil de hacer! En la conferencia de hoy entenderemos en qué partes consta la interacción RMI y cómo configurarla. Lo primero que necesitamos es un cliente y un servidor . No es necesario profundizar demasiado en la terminología informática. En el caso de RMI, se trata simplemente de dos programas. Uno de ellos contendrá algún objeto y el segundo llamará a los métodos de este objeto. Llamar a métodos de un objeto en un programa que se encuentra en otro programa: ¡nunca habíamos hecho esto antes! ¡Es hora de probarlo! :) Para no ahogarnos en la naturaleza, dejemos que nuestro programa sea simple. Por lo general los servidores suelen realizar algún tipo de cálculos que el cliente solicita. Será lo mismo para nosotros. Tendremos como servidor un sencillo programa de calculadora. Ella tendrá un solo método: multiply(). Multiplicará los dos números que le envió el programa cliente y devolverá el resultado. Primero que nada necesitamos una interfaz:
import java.rmi.Remote;
import java.rmi.RemoteException;

public interface Calculator extends Remote {

   int multiply(int x, int y) throws RemoteException;
}
¿Por qué necesitamos una interfaz? El caso es que el trabajo de RMI se basa en la creación de proxies, que estudiaste en una de las conferencias anteriores . Y el trabajo con proxies, como probablemente recordará, se lleva a cabo precisamente a nivel de interfaces, no de clases. ¡Hay 2 requisitos importantes para nuestra interfaz!
  1. Debe heredar la interfaz del token remoto.
  2. Todos sus métodos deben generar una RemoteException (esto no se hace automáticamente en el IDE, ¡debes escribirlo manualmente!).
Ahora necesitamos crear una clase de servidor que implementará nuestra interfaz Calculator. RMI: práctica de uso - 2Aquí todo también es bastante sencillo:
import java.rmi.RemoteException;

public class RemoteCalculationServer implements Calculator {

   @Override
   public int multiply(int x, int y) throws RemoteException {
       return x*y;
   }

}
Ni siquiera hay mucho que comentar aquí :) Ahora necesitamos escribir un programa de servidor que configurará e iniciará nuestra clase de calculadora de servidor. Se verá así:
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 ServerMain {

   public static final String UNIQUE_BINDING_NAME = "server.calculator";

   public static void main(String[] args) throws RemoteException, AlreadyBoundException, InterruptedException {

       final RemoteCalculationServer server = new RemoteCalculationServer();

       final Registry registry = LocateRegistry.createRegistry(2732);

       Remote stub = UnicastRemoteObject.exportObject(server, 0);
       registry.bind(UNIQUE_BINDING_NAME, stub);

       Thread.sleep(Integer.MAX_VALUE);

   }
}
Vamos a resolverlo :) En la primera línea creamos algún tipo de variable de cadena:
public static final String UNIQUE_BINDING_NAME = "server.calculator";
Esta cadena es el nombre exclusivo del objeto remoto . Con este nombre el programa cliente podrá encontrar nuestro servidor: lo verá más adelante. A continuación creamos nuestro objeto calculadora:
final RemoteCalculationServer server = new RemoteCalculationServer();
Todo está claro aquí. Lo siguiente es más interesante:
final Registry registry = LocateRegistry.createRegistry(2732);
Esta cosa llamada Registro es un registro de objetos eliminados . "Eliminado" no en el sentido de que los eliminamos de la computadora, sino en el hecho de que se puede acceder a los objetos de este registro de forma remota desde otros programas :) LocateRegistry.createRegistry()Al método le pasamos el número 2732. Este es el número de puerto. Si no sabes qué es un puerto, puedes leerlo aquí , pero por ahora solo debes recordar que este es un número único mediante el cual otros programas pueden encontrar nuestro registro de objetos (también lo verás a continuación). Vamonos. Veamos qué sucede en la siguiente línea:
Remote stub = UnicastRemoteObject.exportObject(server, 0);
En esta línea creamos un stub . Un stub encapsula todo el proceso de llamada remota dentro de sí mismo. Se puede decir que este es el elemento más importante de RMI. ¿Qué está haciendo?
  1. Recibe toda la información sobre una llamada remota a un método.
  2. Si el método tiene parámetros, el stub los deserializa. ¡Presta atención a este punto! Los parámetros que pase a los métodos para llamadas remotas deben ser serializables (después de todo, se transmitirán a través de la red). No tenemos ese problema: simplemente transmitimos números. Pero si transfieres objetos, ¡no lo olvides!
  3. Después de eso, llama al método deseado.
Pasamos UnicastRemoteObject.exportObject()nuestro objeto de calculadora de servidor al método. De esta manera hacemos posible llamar a sus métodos de forma remota. Sólo nos queda una cosa por hacer:
registry.bind(UNIQUE_BINDING_NAME, stub);
"Registramos" nuestro código auxiliar en el registro de objetos remotos con el nombre que se nos ocurrió al principio. ¡Ahora el cliente puede encontrarlo! Habrás notado que al final ponemos a dormir el hilo principal del programa:
Thread.sleep(Integer.MAX_VALUE);
Sólo necesitamos mantener el servidor funcionando durante mucho tiempo. Ejecutaremos dos métodos en IDEa a la vez main(): primero el del servidor (en la clase ServerMainque ya hemos escrito), y luego el del cliente (en la clase que ClientMainescribiremos a continuación). Es importante que el programa del servidor no se caiga mientras lanzamos el cliente, por lo que simplemente lo ponemos en reposo durante un tiempo prolongado. Seguirá funcionando :) Ahora podemos ejecutar main()nuestro método de servidor. Déjelo ejecutar y espere a que el programa cliente llame a algún método :) ¡Ahora escribamos un programa cliente! Enviará números a nuestro servidor para multiplicarlos.
import java.rmi.NotBoundException;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;

public class ClientMain {

   public static final String UNIQUE_BINDING_NAME = "server.calculator";

   public static void main(String[] args) throws RemoteException, NotBoundException {

       final Registry registry = LocateRegistry.getRegistry(2732);

       Calculator calculator = (Calculator) registry.lookup(UNIQUE_BINDING_NAME);

       int multiplyResult = calculator.multiply(20, 30);

       System.out.println(multiplyResult);
   }
}
Ella parece sencilla. ¿Que está pasando aqui? Primero, el cliente debe conocer el nombre único del objeto cuyos métodos llamará de forma remota. Por lo tanto, en el programa cliente también creamos una variable y public static final String UNIQUE_BINDING_NAME = "server.calculator"; luego en el método main()obtenemos acceso al registro de objetos remotos. Para hacer esto, necesitamos llamar al método LocateRegistry.getRegistry()y pasar allí el número de puerto en el que se creó nuestro registro en el programa ServerMain - puerto 2732 (este número fue elegido para el ejemplo, puede intentar usar otro):
final Registry registry = LocateRegistry.getRegistry(2732);
¡Ahora todo lo que tenemos que hacer es obtener el objeto deseado del registro! ¡Es fácil porque conocemos su nombre único!
Calculator calculator = (Calculator) registry.lookup(UNIQUE_BINDING_NAME);
Preste atención a la conversión de tipos. Lanzamos el objeto resultante a una interfaz Calculatoren lugar de a una clase concreta RemoteCalculationServer . Como dijimos al comienzo de la conferencia, RMI se basa en el uso de un proxy, por lo que una llamada remota está disponible solo para métodos de interfaces, no para clases. Al final, llamamos remotamente a un método multiply()en nuestro objeto e imprimimos el resultado en la consola.
int multiplyResult = calculator.multiply(20, 30);
System.out.println(multiplyResult);
Lanzamos el método main()en la clase ServerMainhace mucho tiempo, ¡es hora de iniciar el método main()en el programa cliente ClientMain! Salida de consola: 600 ¡Eso es todo! Nuestro programa (¡incluso dos!) cumplió con éxito su función :) Si tienes tiempo y ganas, puedes diversificarlo un poco. Por ejemplo, asegúrese de que la calculadora admita las cuatro operaciones estándar y que no se pasen números, sino un objeto como parámetros CalculationInstance(int x, int y). Como material adicional, puede consultar artículos y ejemplos aquí: ¡Nos vemos en las próximas clases! :)
Comentarios
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION