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:

  1. Implementa la interfaz remota compartida, ya sea explícita o implícitamente al extender UnicastRemoteObject que implementa Remote .
  2. Se exporta, ya sea de forma implícita si extiende UnicastRemoteObject , o explícitamente se pasa a UnicastRemoteObject#exportObject .
  3. Enlazado en un registro, ya sea directamente a través del Registry o indirectamente a través de Naming . 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.

  1. Un servidor de inicio de sesión se une a un registro.
  2. 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).
  3. Un cliente llama al passInt del servidor con el nombre del cliente destinatario y un int .
  4. El servidor llama a la half en el cliente del destinatario con ese int . 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:

  1. Ejecutar el servidor de inicio de sesión.
  2. Ejecuta un cliente con los argumentos Client2 Client1 1097 .
  3. 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


Modified text is an extract of the original Stack Overflow Documentation
Licenciado bajo CC BY-SA 3.0
No afiliado a Stack Overflow