Szukaj…


Uwagi

RMI wymaga 3 komponentów: klienta, serwera i wspólnego interfejsu zdalnego. Współdzielony zdalny interfejs definiuje umowę klient-serwer, określając metody, które serwer musi wdrożyć. Interfejs musi być widoczny dla serwera, aby mógł implementować metody; interfejs musi być widoczny dla klienta, aby wiedział, jakie metody („usługi”) zapewnia serwer.
Każdy obiekt implementujący zdalny interfejs może pełnić rolę serwera. W związku z tym relacja klient-serwer, w której serwer może również wywoływać metody w kliencie, jest w rzeczywistości relacją serwer-serwer. Jest to nazywane oddzwanianiem, ponieważ serwer może oddzwonić do „klienta”. Mając to na uwadze, dopuszczalne jest użycie klienta desygnacji dla serwerów, które działają jako takie.

Współdzielony zdalny interfejs to dowolny interfejs rozszerzający Remote . Obiekt, który działa jak serwer, podlega:

  1. Implementuje udostępniony interfejs zdalny, jawnie lub niejawnie, poprzez rozszerzenie UnicastRemoteObject który implementuje Remote .
  2. Eksportowane, niejawnie, jeśli rozszerza UnicastRemoteObject , lub jawnie przez przekazanie do UnicastRemoteObject#exportObject .
  3. Powiązane w rejestrze, bezpośrednio przez Registry lub pośrednio przez Naming . Jest to konieczne tylko do nawiązania początkowej komunikacji, ponieważ kolejne kody pośredniczące mogą być przekazywane bezpośrednio przez RMI.

W konfiguracji projektu projekty klienta i serwera są całkowicie niezwiązane, ale każdy określa wspólny projekt na ścieżce kompilacji. Udostępniony projekt zawiera zdalne interfejsy.

Klient-serwer: wywoływanie metod w jednej maszynie JVM z drugiej

Współdzielony zdalny interfejs:

package remote;

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

public interface RemoteServer extends Remote {

    int stringToInt(String string) throws RemoteException;
}

Serwer implementujący współdzielony zdalny interfejs:

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

Klient wywołuje metodę na serwerze (zdalnie):

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

Wynik:

Otrzymano serwer: „120”
Klient otrzymał: 120

Oddzwonienie: wywoływanie metod na „kliencie”

Przegląd

W tym przykładzie 2 klientów wysyła do siebie informacje za pośrednictwem serwera. Jeden klient wysyła do serwera numer, który jest przekazywany do drugiego klienta. Drugi klient dzieli połowę numeru i wysyła go z powrotem do pierwszego klienta za pośrednictwem serwera. Pierwszy klient robi to samo. Serwer przerywa komunikację, gdy liczba zwracana mu przez któregokolwiek z klientów jest mniejsza niż 10. Wartość zwracana z serwera do klientów (liczba, którą przekonwertowała na ciąg znaków) następnie śledzi proces.

  1. Serwer logowania wiąże się z rejestrem.
  2. Klient wyszukuje serwer logowania i wywołuje metodę login z jego informacjami. Następnie:
    • Serwer logowania przechowuje informacje o kliencie. Zawiera kod pośredniczący klienta z metodami wywołania zwrotnego.
    • Serwer logowania tworzy i zwraca kod pośredniczący serwera („połączenie” lub „sesję”) do klienta w celu zapisania. Zawiera kod pośredniczący serwera wraz z jego metodami, w tym metodą logout (nieużywaną w tym przykładzie).
  3. Klient wywołuje passInt serwera z nazwą klienta odbiorcy i int .
  4. Serwer wywołuje half na kliencie odbiorcy z tą int . To inicjuje komunikację w obie strony (połączenia i połączenia zwrotne) do momentu zatrzymania przez serwer.

Współdzielone zdalne interfejsy

Serwer logowania:

package callbackRemote;

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

public interface RemoteLogin extends Remote {

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

Serwer:

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

Klient:

package callbackRemote;

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

public interface RemoteClient extends Remote {

    void half(int i) throws RemoteException;
}

Wdrożenia

Serwer logowania:

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

Serwer:

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

Klient:

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

Uruchamianie przykładu:

  1. Uruchom serwer logowania.
  2. Uruchom klienta z argumentami Client2 Client1 1097 .
  3. Uruchom klienta z argumentami Client1 Client2 1098 .

Wyjścia pojawią się w 3 konsolach, ponieważ są 3 maszyny JVM. tutaj są zlepione:

Klient2 zalogowany
Klient1 zalogowany
Serwer odebrany od klienta1: 120
Serwer otrzymany od klienta2: 60
Serwer otrzymał od klienta1: 30
Serwer otrzymany od klienta2: 15
Serwer otrzymany od klienta1: 7
Klient1 otrzymał: „7”
Otrzymano klient2: „15”
Klient1 otrzymał: „30”
Klient2 otrzymał: „60”

Prosty przykład RMI z implementacją klienta i serwera

Jest to prosty przykład RMI z pięcioma klasami Java i dwoma pakietami, serwerem i klientem .

Pakiet serwera

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

Pakiet klienta

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

Przetestuj swoją aplikację

  • Uruchom główną metodę Server.java. Wynik:
Server : Registry created.
Server : PersonList registered
  • Uruchom główną metodę PersonTest.java. Wynik:
Peter Pan
Pippi Langstrumpf


Modified text is an extract of the original Stack Overflow Documentation
Licencjonowany na podstawie CC BY-SA 3.0
Nie związany z Stack Overflow