Java Language
Invocación de método remoto (RMI)
Buscar..
Observaciones
RMI requiere 3 componentes: cliente, servidor y una interfaz remota compartida. La interfaz remota compartida define el contrato cliente-servidor especificando los métodos que debe implementar un servidor. La interfaz debe ser visible para el servidor para que pueda implementar los métodos; la interfaz debe ser visible para el cliente para que sepa qué métodos ("servicios") proporciona el servidor.
Cualquier objeto que implemente una interfaz remota está destinado a asumir el rol de un servidor. Como tal, una relación cliente-servidor en la que el servidor también puede invocar métodos en el cliente es, de hecho, una relación servidor-servidor. Esto se denomina devolución de llamada ya que el servidor puede devolver la llamada al "cliente". Teniendo esto en cuenta, es aceptable utilizar el cliente de designación para los servidores que funcionan como tales.
La interfaz remota compartida es cualquier interfaz que se extiende a Remote
. Un objeto que funciona como un servidor experimenta lo siguiente:
- Implementa la interfaz remota compartida, ya sea explícita o implícitamente al extender
UnicastRemoteObject
que implementaRemote
. - Se exporta, ya sea de forma implícita si extiende
UnicastRemoteObject
, o explícitamente se pasa aUnicastRemoteObject#exportObject
. - Enlazado en un registro, ya sea directamente a través del
Registry
o indirectamente a través deNaming
. Esto solo es necesario para establecer una comunicación inicial, ya que se pueden pasar más apéndices directamente a través de RMI.
En la configuración del proyecto, los proyectos de cliente y servidor no están relacionados, pero cada uno especifica un proyecto compartido en su ruta de compilación. El proyecto compartido contiene las interfaces remotas.
Cliente-Servidor: invocando métodos en una JVM desde otra
La interfaz remota compartida:
package remote;
import java.rmi.Remote;
import java.rmi.RemoteException;
public interface RemoteServer extends Remote {
int stringToInt(String string) throws RemoteException;
}
El servidor que implementa la interfaz remota compartida:
package server;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import java.rmi.server.UnicastRemoteObject;
import remote.RemoteServer;
public class Server implements RemoteServer {
@Override
public int stringToInt(String string) throws RemoteException {
System.out.println("Server received: \"" + string + "\"");
return Integer.parseInt(string);
}
public static void main(String[] args) {
try {
Registry reg = LocateRegistry.createRegistry(Registry.REGISTRY_PORT);
Server server = new Server();
UnicastRemoteObject.exportObject(server, Registry.REGISTRY_PORT);
reg.rebind("ServerName", server);
} catch (RemoteException e) {
e.printStackTrace();
}
}
}
El cliente que invoca un método en el servidor (de forma remota):
package client;
import java.rmi.NotBoundException;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import remote.RemoteServer;
public class Client {
static RemoteServer server;
public static void main(String[] args) {
try {
Registry reg = LocateRegistry.getRegistry();
server = (RemoteServer) reg.lookup("ServerName");
} catch (RemoteException | NotBoundException e) {
e.printStackTrace();
}
Client client = new Client();
client.callServer();
}
void callServer() {
try {
int i = server.stringToInt("120");
System.out.println("Client received: " + i);
} catch (RemoteException e) {
e.printStackTrace();
}
}
}
Salida:
Servidor recibido: "120"
Cliente recibido: 120
Devolución de llamada: invocar métodos en un "cliente"
Visión general
En este ejemplo, 2 clientes se envían información a través de un servidor. Un cliente envía al servidor un número que se transmite al segundo cliente. El segundo cliente divide el número a la mitad y lo envía de vuelta al primer cliente a través del servidor. El primer cliente hace lo mismo. El servidor detiene la comunicación cuando el número devuelto por cualquiera de los clientes es inferior a 10. El valor devuelto por el servidor a los clientes (el número que se convirtió en representación de cadena) luego realiza un seguimiento del proceso.
- Un servidor de inicio de sesión se une a un registro.
- Un cliente busca el servidor de inicio de sesión y llama al método de
login
con su información. Entonces:- El servidor de inicio de sesión almacena la información del cliente. Incluye el talón del cliente con los métodos de devolución de llamada.
- El servidor de inicio de sesión crea y devuelve un código auxiliar de servidor ("conexión" o "sesión") al cliente para que lo almacene. Incluye el código auxiliar del servidor con sus métodos, incluido un método de
logout
(no utilizado en este ejemplo).
- Un cliente llama al
passInt
del servidor con el nombre del cliente destinatario y unint
. - El servidor llama a la
half
en el cliente del destinatario con eseint
. Esto inicia una comunicación de ida y vuelta (llamadas y devoluciones de llamada) hasta que el servidor la detiene.
Las interfaces remotas compartidas
El servidor de inicio de sesión:
package callbackRemote;
import java.rmi.Remote;
import java.rmi.RemoteException;
public interface RemoteLogin extends Remote {
RemoteConnection login(String name, RemoteClient client) throws RemoteException;
}
El servidor:
package callbackRemote;
import java.rmi.Remote;
import java.rmi.RemoteException;
public interface RemoteConnection extends Remote {
void logout() throws RemoteException;
String passInt(String name, int i) throws RemoteException;
}
El cliente:
package callbackRemote;
import java.rmi.Remote;
import java.rmi.RemoteException;
public interface RemoteClient extends Remote {
void half(int i) throws RemoteException;
}
Las implementaciones
El servidor de inicio de sesión:
package callbackServer;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import java.rmi.server.UnicastRemoteObject;
import java.util.HashMap;
import java.util.Map;
import callbackRemote.RemoteClient;
import callbackRemote.RemoteConnection;
import callbackRemote.RemoteLogin;
public class LoginServer implements RemoteLogin {
static Map<String, RemoteClient> clients = new HashMap<>();
@Override
public RemoteConnection login(String name, RemoteClient client) {
Connection connection = new Connection(name, client);
clients.put(name, client);
System.out.println(name + " logged in");
return connection;
}
public static void main(String[] args) {
try {
Registry reg = LocateRegistry.createRegistry(Registry.REGISTRY_PORT);
LoginServer server = new LoginServer();
UnicastRemoteObject.exportObject(server, Registry.REGISTRY_PORT);
reg.rebind("LoginServerName", server);
} catch (RemoteException e) {
e.printStackTrace();
}
}
}
El servidor:
package callbackServer;
import java.rmi.NoSuchObjectException;
import java.rmi.RemoteException;
import java.rmi.registry.Registry;
import java.rmi.server.UnicastRemoteObject;
import java.rmi.server.Unreferenced;
import callbackRemote.RemoteClient;
import callbackRemote.RemoteConnection;
public class Connection implements RemoteConnection, Unreferenced {
RemoteClient client;
String name;
public Connection(String name, RemoteClient client) {
this.client = client;
this.name = name;
try {
UnicastRemoteObject.exportObject(this, Registry.REGISTRY_PORT);
} catch (RemoteException e) {
e.printStackTrace();
}
}
@Override
public void unreferenced() {
try {
UnicastRemoteObject.unexportObject(this, true);
} catch (NoSuchObjectException e) {
e.printStackTrace();
}
}
@Override
public void logout() {
try {
UnicastRemoteObject.unexportObject(this, true);
} catch (NoSuchObjectException e) {
e.printStackTrace();
}
}
@Override
public String passInt(String recipient, int i) {
System.out.println("Server received from " + name + ":" + i);
if (i < 10)
return String.valueOf(i);
RemoteClient client = LoginServer.clients.get(recipient);
try {
client.half(i);
} catch (RemoteException e) {
e.printStackTrace();
}
return String.valueOf(i);
}
}
El cliente:
package callbackClient;
import java.rmi.NotBoundException;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import java.rmi.server.UnicastRemoteObject;
import callbackRemote.RemoteClient;
import callbackRemote.RemoteConnection;
import callbackRemote.RemoteLogin;
public class Client implements RemoteClient {
RemoteConnection connection;
String name, target;
Client(String name, String target) {
this.name = name;
this.target = target;
}
public static void main(String[] args) {
Client client = new Client(args[0], args[1]);
try {
Registry reg = LocateRegistry.getRegistry();
RemoteLogin login = (RemoteLogin) reg.lookup("LoginServerName");
UnicastRemoteObject.exportObject(client, Integer.parseInt(args[2]));
client.connection = login.login(client.name, client);
} catch (RemoteException | NotBoundException e) {
e.printStackTrace();
}
if ("Client1".equals(client.name)) {
try {
client.connection.passInt(client.target, 120);
} catch (RemoteException e) {
e.printStackTrace();
}
}
}
@Override
public void half(int i) throws RemoteException {
String result = connection.passInt(target, i / 2);
System.out.println(name + " received: \"" + result + "\"");
}
}
Ejecutando el ejemplo:
- Ejecutar el servidor de inicio de sesión.
- Ejecuta un cliente con los argumentos
Client2 Client1 1097
. - Ejecutar un cliente con los argumentos
Client1 Client2 1098
.
Las salidas aparecerán en 3 consolas ya que hay 3 JVM. Aquí están agrupados:
Client2 ha iniciado sesión
Client1 ha iniciado sesión
Servidor recibido de Cliente1: 120
Servidor recibido de Cliente2: 60
Servidor recibido de Cliente1: 30
Servidor recibido de Cliente2: 15
Servidor recibido de Cliente1: 7
Cliente1 recibido: "7"
Cliente2 recibido: "15"
Cliente1 recibido: "30"
Cliente2 recibido: "60"
Ejemplo de RMI simple con implementación de cliente y servidor
Este es un ejemplo simple de RMI con cinco clases Java y dos paquetes, servidor y cliente .
Paquete de servidor
PersonListInterface.java
public interface PersonListInterface extends Remote
{
/**
* This interface is used by both client and server
* @return List of Persons
* @throws RemoteException
*/
ArrayList<String> getPersonList() throws RemoteException;
}
PersonListImplementation.java
public class PersonListImplementation
extends UnicastRemoteObject
implements PersonListInterface
{
private static final long serialVersionUID = 1L;
// standard constructor needs to be available
public PersonListImplementation() throws RemoteException
{}
/**
* Implementation of "PersonListInterface"
* @throws RemoteException
*/
@Override
public ArrayList<String> getPersonList() throws RemoteException
{
ArrayList<String> personList = new ArrayList<String>();
personList.add("Peter Pan");
personList.add("Pippi Langstrumpf");
// add your name here :)
return personList;
}
}
Servidor.java
public class Server {
/**
* Register servicer to the known public methods
*/
private static void createServer() {
try {
// Register registry with standard port 1099
LocateRegistry.createRegistry(Registry.REGISTRY_PORT);
System.out.println("Server : Registry created.");
// Register PersonList to registry
Naming.rebind("PersonList", new PersonListImplementation());
System.out.println("Server : PersonList registered");
} catch (final IOException e) {
e.printStackTrace();
}
}
public static void main(final String[] args) {
createServer();
}
}
Paquete de cliente
PersonListLocal.java
public class PersonListLocal {
private static PersonListLocal instance;
private PersonListInterface personList;
/**
* Create a singleton instance
*/
private PersonListLocal() {
try {
// Lookup to the local running server with port 1099
final Registry registry = LocateRegistry.getRegistry("localhost",
Registry.REGISTRY_PORT);
// Lookup to the registered "PersonList"
personList = (PersonListInterface) registry.lookup("PersonList");
} catch (final RemoteException e) {
e.printStackTrace();
} catch (final NotBoundException e) {
e.printStackTrace();
}
}
public static PersonListLocal getInstance() {
if (instance == null) {
instance = new PersonListLocal();
}
return instance;
}
/**
* Returns the servers PersonList
*/
public ArrayList<String> getPersonList() {
if (instance != null) {
try {
return personList.getPersonList();
} catch (final RemoteException e) {
e.printStackTrace();
}
}
return new ArrayList<>();
}
}
PersonTest.java
public class PersonTest
{
public static void main(String[] args)
{
// get (local) PersonList
ArrayList<String> personList = PersonListLocal.getInstance().getPersonList();
// print all persons
for(String person : personList)
{
System.out.println(person);
}
}
}
Prueba tu aplicación
- Iniciar el método principal de Server.java. Salida:
Server : Registry created.
Server : PersonList registered
- Iniciar el método principal de PersonTest.java. Salida:
Peter Pan
Pippi Langstrumpf