Ricerca…


Osservazioni

RMI richiede 3 componenti: client, server e un'interfaccia remota condivisa. L'interfaccia remota condivisa definisce il contratto client-server specificando i metodi che un server deve implementare. L'interfaccia deve essere visibile al server in modo che possa implementare i metodi; l'interfaccia deve essere visibile al client in modo che conosca i metodi ("servizi") forniti dal server.
Qualsiasi oggetto che implementa un'interfaccia remota è destinato a svolgere il ruolo di server. Come tale, una relazione client-server in cui il server può anche invocare metodi nel client è in realtà una relazione server-server. Questo è chiamato callback poiché il server può richiamare il "client". Con questo in mente, è accettabile utilizzare il client di designazione per i server che funzionano come tali.

L'interfaccia remota condivisa è un'interfaccia che estende Remote . Un oggetto che funziona come server subisce quanto segue:

  1. Implementa l'interfaccia remota condivisa, esplicitamente o implicitamente, estendendo UnicastRemoteObject che implementa Remote .
  2. Esportato, implicitamente se estende UnicastRemoteObject o esplicitamente passando a UnicastRemoteObject#exportObject .
  3. Associato in un registro, direttamente tramite il Registry o indirettamente tramite Naming . Questo è necessario solo per stabilire una comunicazione iniziale poiché ulteriori stub possono essere passati direttamente tramite RMI.

Nell'impostazione del progetto, i progetti client e server non sono completamente correlati, ma ognuno specifica un progetto condiviso nel suo percorso di generazione. Il progetto condiviso contiene le interfacce remote.

Client-Server: richiamo di metodi in una JVM da un'altra

L'interfaccia remota condivisa:

package remote;

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

public interface RemoteServer extends Remote {

    int stringToInt(String string) throws RemoteException;
}

Il server che implementa l'interfaccia remota condivisa:

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();
        }
    }
}

Il client che richiama un metodo sul server (in remoto):

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();
        }
    }
}

Produzione:

Server ricevuto: "120"
Cliente ricevuto: 120

Callback: invocazione di metodi su un "client"

Panoramica

In questo esempio 2 client inviano informazioni reciprocamente attraverso un server. Un client invia al server un numero che viene inoltrato al secondo client. Il secondo client dimezza il numero e lo invia al primo client attraverso il server. Il primo cliente fa lo stesso. Il server interrompe la comunicazione quando il numero restituito da uno dei client è inferiore a 10. Il valore restituito dal server ai client (il numero convertito in rappresentazione stringa) quindi retrocede il processo.

  1. Un server di login si lega a un registro.
  2. Un client cerca il server di login e chiama il metodo di login con le sue informazioni. Poi:
    • Il server di login memorizza le informazioni del cliente. Include lo stub del cliente con i metodi di callback.
    • Il server di login crea e restituisce un server stub ("connessione" o "sessione") al client da memorizzare. Include lo stub del server con i suoi metodi incluso un metodo di logout (non utilizzato in questo esempio).
  3. Un client chiama il passInt del server con il nome del client del destinatario e un int .
  4. Il server chiama la half sul client destinatario con quella int . Ciò avvia una comunicazione avanti e indietro (chiamate e callback) finché non viene arrestata dal server.

Le interfacce remote condivise

Il server di login:

package callbackRemote;

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

public interface RemoteLogin extends Remote {

    RemoteConnection login(String name, RemoteClient client) throws RemoteException;
}

Il server:

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;
}

Il cliente:

package callbackRemote;

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

public interface RemoteClient extends Remote {

    void half(int i) throws RemoteException;
}

Le implementazioni

Il server di login:

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();
        }
    }
}

Il server:

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);
    }
}

Il 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 + "\"");
    }
}

Esecuzione dell'esempio:

  1. Esegui il server di login.
  2. Esegui un client con gli argomenti Client2 Client1 1097 .
  3. Esegui un client con gli argomenti Client1 Client2 1098 .

Le uscite appariranno su 3 console poiché ci sono 3 JVM. eccoli raggruppati insieme:

Client2 registrato
Client1 loggato
Server ricevuto da Client1: 120
Server ricevuto da Client2: 60
Server ricevuto da Client1: 30
Server ricevuto da Client2: 15
Server ricevuto da Client1: 7
Client1 ricevuto: "7"
Client2 ricevuto: "15"
Client1 ricevuto: "30"
Client2 ricevuto: "60"

Esempio RMI semplice con implementazione client e server

Questo è un semplice esempio RMI con cinque classi Java e due pacchetti, server e client .

Pacchetto server

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;
    }
}

Server.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();
    }
}

Pacchetto del 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);
        }
    }
}

Metti alla prova la tua domanda

  • Avvia il metodo principale di Server.java. Produzione:
Server : Registry created.
Server : PersonList registered
  • Avvia il metodo principale di PersonTest.java. Produzione:
Peter Pan
Pippi Langstrumpf


Modified text is an extract of the original Stack Overflow Documentation
Autorizzato sotto CC BY-SA 3.0
Non affiliato con Stack Overflow