Zoeken…


Opmerkingen

RMI vereist 3 componenten: client, server en een gedeelde externe interface. De gedeelde externe interface definieert het client-servercontract door de methoden op te geven die een server moet implementeren. De interface moet zichtbaar zijn voor de server zodat deze de methoden kan implementeren; de interface moet zichtbaar zijn voor de client zodat deze weet welke methoden ("services") de server biedt.
Elk object dat een externe interface implementeert, is bedoeld om de rol van server op zich te nemen. Als zodanig is een client-serverrelatie waarin de server ook methoden in de client kan oproepen in feite een server-serverrelatie. Dit wordt callback genoemd omdat de server de "client" kan terugbellen. Met dit in het achterhoofd, is het acceptabel om de benaming cliënt voor de servers die functie als zodanig.

De gedeelde externe interface is elke interface die Remote uitbreidt. Een object dat functioneert als een server ondergaat het volgende:

  1. Implementeert de gedeelde externe interface, expliciet of impliciet door UnicastRemoteObject breiden dat Remote implementeert.
  2. Geëxporteerd, impliciet als het UnicastRemoteObject , of expliciet door te geven aan UnicastRemoteObject#exportObject .
  3. Gebonden in een register, rechtstreeks via het Registry of indirect via Naming . Dit is alleen nodig voor het tot stand brengen van initiële communicatie, omdat verdere stubs direct kunnen worden doorgegeven via RMI.

In de projectconfiguratie staan de client- en serverprojecten volledig los, maar elk specificeert een gedeeld project in het buildpad. Het gedeelde project bevat de externe interfaces.

Client-server: methoden in de ene JVM van de andere aanroepen

De gedeelde externe interface:

package remote;

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

public interface RemoteServer extends Remote {

    int stringToInt(String string) throws RemoteException;
}

De server die de gedeelde externe interface implementeert:

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

De client die (op afstand) een methode op de server aanroept:

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

Output:

Server ontvangen: "120"
Klant ontvangen: 120

Terugbellen: methoden aanroepen op een "client"

Overzicht

In dit voorbeeld sturen 2 clients informatie naar elkaar via een server. Een client stuurt de server een nummer dat wordt doorgestuurd naar de tweede client. De tweede client halveert het nummer en stuurt het via de server terug naar de eerste client. De eerste client doet hetzelfde. De server stopt de communicatie wanneer het nummer dat door een van de clients wordt geretourneerd minder is dan 10. De retourwaarde van de server naar de clients (het nummer dat is geconverteerd naar stringvoorstelling) gaat vervolgens terug naar het proces.

  1. Een login-server bindt zich aan een register.
  2. Een client zoekt de inlogserver op en roept de login met zijn informatie. Vervolgens:
    • De aanmeldingsserver slaat de clientinformatie op. Het bevat de stub van de client met de callback-methoden.
    • De inlogserver maakt en retourneert een serverstub ("verbinding" of "sessie") naar de client om op te slaan. Het bevat de stub van de server met zijn methoden, waaronder een logout (in dit voorbeeld niet gebruikt).
  3. Een client roept de passInt van de server passInt met de naam van de ontvangende client en een int .
  4. De server roept de half van de ontvangende client met die int . Dit initieert een heen en weer communicatie (call en callbacks) totdat deze door de server wordt gestopt.

De gedeelde externe interfaces

De inlogserver:

package callbackRemote;

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

public interface RemoteLogin extends Remote {

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

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

De cliënt:

package callbackRemote;

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

public interface RemoteClient extends Remote {

    void half(int i) throws RemoteException;
}

De implementaties

De inlogserver:

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

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

De cliënt:

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

Het voorbeeld uitvoeren:

  1. Voer de inlogserver uit.
  2. Voer een client uit met de argumenten Client2 Client1 1097 .
  3. Voer een client uit met de argumenten Client1 Client2 1098 .

De uitgangen verschijnen in 3 consoles omdat er 3 JVM's zijn. hier worden ze samengevoegd:

Client2 ingelogd
Client1 ingelogd
Server ontvangen van client1: 120
Server ontvangen van client2: 60
Server ontvangen van client1: 30
Server ontvangen van client2: 15
Server ontvangen van client1: 7
Klant1 ontvangen: "7"
Client2 ontvangen: "15"
Klant1 ontvangen: "30"
Client2 ontvangen: "60"

Eenvoudig RMI-voorbeeld met client- en serverimplementatie

Dit is een eenvoudig RMI-voorbeeld met vijf Java-klassen en twee pakketten, server en client .

Serverpakket

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

Client pakket

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

Test uw toepassing

  • Start de hoofdmethode van Server.java. Output:
Server : Registry created.
Server : PersonList registered
  • Start de hoofdmethode van PersonTest.java. Output:
Peter Pan
Pippi Langstrumpf


Modified text is an extract of the original Stack Overflow Documentation
Licentie onder CC BY-SA 3.0
Niet aangesloten bij Stack Overflow