Java Language
Remote Method Invocation (RMI)
Suche…
Bemerkungen
RMI erfordert 3 Komponenten: Client, Server und eine gemeinsam genutzte Remote-Schnittstelle. Die gemeinsam genutzte Remote-Schnittstelle definiert den Client-Server-Vertrag durch Angabe der Methoden, die ein Server implementieren muss. Die Schnittstelle muss für den Server sichtbar sein, damit die Methoden implementiert werden können. Die Schnittstelle muss für den Client sichtbar sein, damit er weiß, welche Methoden ("Dienste") der Server bereitstellt.
Jedes Objekt, das eine Remote-Schnittstelle implementiert, übernimmt die Rolle eines Servers. Somit ist eine Client-Server-Beziehung, in der der Server auch Methoden im Client aufrufen kann, eine Server-Server-Beziehung. Dies wird als Rückruf bezeichnet, da der Server den "Client" zurückrufen kann. Aus diesem Grund ist es akzeptabel, den Designation Client für die Server zu verwenden, die als solche funktionieren.
Die gemeinsam genutzte Remote-Schnittstelle ist eine beliebige Schnittstelle, die Remote
. Ein Objekt, das als Server fungiert, durchläuft Folgendes:
- Implementiert die freigegebene Remote-Schnittstelle entweder explizit oder implizit durch Erweiterung von
UnicastRemoteObject
dasRemote
implementiert. - Exportiert, entweder implizit, wenn
UnicastRemoteObject
erweitertUnicastRemoteObject
, oder explizit durchUnicastRemoteObject#exportObject
anUnicastRemoteObject#exportObject
. - In eine Registry eingebunden, entweder direkt über die
Registry
oder indirekt über dieNaming
. Dies ist nur für den Aufbau der Erstkommunikation notwendig, da weitere Stubs direkt über RMI übergeben werden können.
In der Projektkonfiguration sind die Client- und Serverprojekte völlig unabhängig voneinander, aber jedes gibt ein freigegebenes Projekt in seinem Erstellungspfad an. Das freigegebene Projekt enthält die Remote-Schnittstellen.
Client-Server: Aufrufen von Methoden in einer JVM von einer anderen
Die gemeinsam genutzte Remote-Schnittstelle:
package remote;
import java.rmi.Remote;
import java.rmi.RemoteException;
public interface RemoteServer extends Remote {
int stringToInt(String string) throws RemoteException;
}
Der Server, der die freigegebene Remote-Schnittstelle implementiert:
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();
}
}
}
Der Client, der eine Methode auf dem Server (remote) aufruft:
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();
}
}
}
Ausgabe:
Server erhalten: "120"
Kunde erhielt: 120
Callback: Aufrufen von Methoden auf einem "Client"
Überblick
In diesem Beispiel senden 2 Clients Informationen über einen Server. Ein Client sendet dem Server eine Nummer, die an den zweiten Client weitergeleitet wird. Der zweite Client halbiert die Nummer und sendet sie über den Server an den ersten Client zurück. Der erste Client macht das Gleiche. Der Server stoppt die Kommunikation, wenn die von einem der Clients zurückgegebene Nummer weniger als 10 ist. Der Rückgabewert vom Server an die Clients (die Nummer, die er in eine String-Darstellung umgewandelt hat) führt dann den Prozess zurück.
- Ein Anmeldeserver bindet sich an eine Registry.
- Ein Client sucht den Login-Server und ruft die
login
Methode mit seinen Informationen auf. Dann:- Der Anmeldeserver speichert die Clientinformationen. Es enthält den Stub des Clients mit den Rückmeldemethoden.
- Der Anmeldeserver erstellt einen Serverstub ("Verbindung" oder "Sitzung") und gibt ihn an den zu speichernden Client zurück. Es enthält den Stub des Servers mit seinen Methoden, einschließlich einer
logout
(in diesem Beispiel nicht verwendet).
- Ein Client ruft das
passInt
des Servers mit dem Namen des Empfängerclients und einemint
. - Der Server ruft die
half
des Empfängerclients mit diesemint
. Dadurch wird eine Hin- und Her-Kommunikation (Anrufe und Rückrufe) eingeleitet, bis der Server angehalten wird.
Die gemeinsam genutzten Remote-Schnittstellen
Der Login-Server:
package callbackRemote;
import java.rmi.Remote;
import java.rmi.RemoteException;
public interface RemoteLogin extends Remote {
RemoteConnection login(String name, RemoteClient client) throws RemoteException;
}
Der 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;
}
Der Kunde:
package callbackRemote;
import java.rmi.Remote;
import java.rmi.RemoteException;
public interface RemoteClient extends Remote {
void half(int i) throws RemoteException;
}
Die Implementierungen
Der Login-Server:
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();
}
}
}
Der 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);
}
}
Der Kunde:
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 + "\"");
}
}
Das Beispiel ausführen:
- Führen Sie den Login-Server aus.
- Führen Sie einen Client mit den Argumenten
Client2 Client1 1097
. - Führen Sie einen Client mit den Argumenten
Client1 Client2 1098
.
Die Ausgänge erscheinen in 3 Konsolen, da es 3 JVMs gibt. hier sind sie zusammengeworfen:
Client2 ist angemeldet
Client1 angemeldet
Server erhielt von Client1: 120
Server erhalten von Client2: 60
Server erhielt von Client1: 30
Server erhalten von Client2: 15
Server erhalten von Client1: 7
Client1 erhielt: "7"
Client2 erhalten: "15"
Client1 erhielt: "30"
Client2 erhalten: "60"
Einfaches RMI-Beispiel mit Client- und Server-Implementierung
Dies ist ein einfaches RMI-Beispiel mit fünf Java-Klassen und zwei Paketen ( Server und Client) .
Server-Paket
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-Paket
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);
}
}
}
Testen Sie Ihre Bewerbung
- Starten Sie die Hauptmethode von Server.java. Ausgabe:
Server : Registry created.
Server : PersonList registered
- Starten Sie die Hauptmethode von PersonTest.java. Ausgabe:
Peter Pan
Pippi Langstrumpf