Java Language Devolución de llamada: invocar métodos en un "cliente"


Ejemplo

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"