Sök…


Anmärkningar

RMI kräver tre komponenter: klient, server och ett delat fjärrgränssnitt. Det delade fjärrgränssnittet definierar klient-serverkontraktet genom att ange vilka metoder en server måste implementera. Gränssnittet måste vara synligt för servern så att det kan implementera metoderna; gränssnittet måste vara synligt för klienten så att det vet vilka metoder ("tjänster") servern tillhandahåller.
Varje objekt som implementerar ett fjärrgränssnitt är avsett att ta rollen som en server. Som sådan är en klient-server-relation där servern också kan åberopa metoder i klienten i själva verket vara en server-server-relation. Detta kallas återuppringning eftersom servern kan ringa tillbaka "klienten". Med detta i åtanke är det acceptabelt att använda beteckningen klient för de servrar som fungerar som sådana.

Det delade fjärrgränssnittet är alla gränssnitt som utvidgar Remote . Ett objekt som fungerar som en server genomgår följande:

  1. Implementerar det delade fjärrgränssnittet, antingen uttryckligen eller implicit genom att utöka UnicastRemoteObject som implementerar Remote .
  2. Exporteras, antingen implicit om det utvidgar UnicastRemoteObject , eller uttryckligen genom att skickas till UnicastRemoteObject#exportObject .
  3. Bindas i ett register, antingen direkt genom Registry eller indirekt genom Naming . Detta är endast nödvändigt för att etablera initial kommunikation eftersom ytterligare stubber kan överföras direkt via RMI.

I projektuppsättningen är klient- och serverprojekten helt oberoende, men var och en anger ett delat projekt i sin byggväg. Det delade projektet innehåller fjärrgränssnitten.

Klient-server: åberopa metoder i en JVM från en annan

Det delade fjärrgränssnittet:

package remote;

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

public interface RemoteServer extends Remote {

    int stringToInt(String string) throws RemoteException;
}

Servern som implementerar det delade fjärrgränssnittet:

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

Klienten åberopar en metod på servern (på distans):

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

Produktion:

Servern mottagen: "120"
Kunden fick: 120

Återuppringning: åberopa metoder på en "klient"

Översikt

I det här exemplet skickar 2 klienter information till varandra via en server. En klient skickar servern ett nummer som vidarebefordras till den andra klienten. Den andra klienten halverar numret och skickar tillbaka det till den första klienten via servern. Den första klienten gör samma sak. Servern stoppar kommunikationen när numret som returneras till den av någon av klienterna är mindre än 10. Returvärdet från servern till klienterna (numret som det fick konverterat till strängrepresentation) spårar sedan tillbaka processen.

  1. En inloggningsserver binder sig till ett register.
  2. En klient letar upp inloggningsservern och ringer login med dess information. Sedan:
    • Inloggningsservern lagrar klientinformationen. Det inkluderar klientens stubb med återuppringningsmetoderna.
    • Inloggningsservern skapar och returnerar en serverstub ("anslutning" eller "session") till klienten som ska lagras. Det inkluderar logout med sina metoder inklusive en logout (oanvänd i detta exempel).
  3. En klient anropar serverns passInt med namnet på mottagarklienten och en int .
  4. Servern anropar half på mottagarklienten med det int . Detta initierar en fram och tillbaka (samtal och återuppringning) -kommunikation tills den stoppas av servern.

De delade fjärrgränssnitten

Inloggningsservern:

package callbackRemote;

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

public interface RemoteLogin extends Remote {

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

Servern:

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

Klienten:

package callbackRemote;

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

public interface RemoteClient extends Remote {

    void half(int i) throws RemoteException;
}

Implementeringarna

Inloggningsservern:

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

Servern:

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

Klienten:

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

Exempel:

  1. Kör inloggningsservern.
  2. Kör en klient med argumenten Client2 Client1 1097 .
  3. Kör en klient med argumenten Client1 Client2 1098 .

Utgångarna kommer att visas i tre konsoler eftersom det finns 3 JVM: er. här klumpas de samman:

Client2 inloggad
Klient1 inloggad
Server mottagen från klient1: 120
Server mottagen från Client2: 60
Server mottagen från Client1: 30
Server mottagen från Client2: 15
Server mottagen från Client1: 7
Klient1 fått: "7"
Klient2 fick: "15"
Klient1 fått: "30"
Klient2 fick: "60"

Enkelt RMI-exempel med klient- och serverimplementering

Detta är ett enkelt RMI-exempel med fem Java-klasser och två paket, server och klient .

Serverpaket

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

Klientpaket

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

Testa din ansökan

  • Starta huvudmetoden för Server.java. Produktion:
Server : Registry created.
Server : PersonList registered
  • Starta huvudmetoden för PersonTest.java. Produktion:
Peter Pan
Pippi Langstrumpf


Modified text is an extract of the original Stack Overflow Documentation
Licensierat under CC BY-SA 3.0
Inte anslutet till Stack Overflow