Einfache RMI-Anwendung mit Java


Da ich mich gera­de im Rah­men mei­nes Stu­di­ums mit RMI beschäf­ti­gen muss, dabei aber immer wie­der auf ver­al­te­te Tuto­ri­als gestos­sen bin, ab Ver­si­on 5 ver­hält sich RMI etwas anders als noch unter den Vor­gän­ger­ver­sio­nen, wer­de ich an die­ser Stel­le eine kur­zes und knap­pes Tuto­ri­al zum Erstel­len einer sehr simp­len RMI-Anwen­dung bereitstellen.

RMI steht für Remo­te Method Invo­ca­ti­on und bedeu­tet in etwa so viel wie “Ent­fern­ter Metho­den­auf­ruf”. Sinn und Zweck der Übung ist es, Daten zwi­schen Ser­ver und Cli­ent aus­zu­tau­schen, indem die Metho­den des jeweils ande­ren Sys­tems auf­ge­ru­fen wer­den. Gere­gelt wird all dies über ein Inter­face, in dem die zum ent­fern­ten Auf­ruf bestimm­ten Metho­den defi­niert wer­den. Mit die­sem Inter­face möch­te ich mei­ne Kurz­ein­füh­rung nun auch beginnen:


package de.ulfklose.rmi.tryouts;

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

public interface ServerInterface extends Remote
{
int getValue() throws RemoteException;
}

In die­sem Inter­face, ServerInterface.java, haben wir nun eine Metho­de namens getVa­lue() defi­niert, die eine Remo­teEx­cep­ti­on wirft, soll­te beim Trans­fer der Daten irgend­et­was schief lau­fen. Die Imports sind ver­pflich­tend, da unser Inter­face Remo­te aus dem Packa­ge java.rmi exten­ded und die eben erwähn­te Remo­teEx­cep­ti­on wer­fen soll.

Jetzt machen wir uns an die Imple­men­tie­rung des Ser­vers. Hier erst mal der Code:


package de.ulfklose.rmi.tryouts;

import java.rmi.Naming;
import java.rmi.RemoteException;
import java.net.MalformedURLException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import java.rmi.server.UnicastRemoteObject;

public class Server extends UnicastRemoteObject implements ServerInterface
{
private int value;
Server() throws RemoteException
{
super();
this.value = 3; // Der Variablen int den Integer-Wert 3 zu weisen
}

public int getValue() throws RemoteException
{
System.out.println("getValue() wurde aufgerufen"); // Server gibt bei jedem Client-Aufruf von getValue() diesen String aus
return this.value; // Server übermittelt aktuellen Wert von "value" an Client
}

public static void main(String[] args)
{
try {
LocateRegistry.createRegistry(Registry.REGISTRY_PORT); // Server an der Registry anmelden
System.out.println("Server registered, up and running."); // kurze Statusmeldung an der Konsole des Servers ausgeben
}
catch (RemoteException ex) {
System.out.println(ex.getMessage());
}
try {
Naming.rebind("Server", new Server()); // Server-Objekt mit dem Namen "Server" erstellen, dies ist nun der Server-Name
}
catch (MalformedURLException ex) {
System.out.println(ex.getMessage());
}
catch (RemoteException ex) {
System.out.println(ex.getMessage());
}
}
}

Das war’s schon. Wich­tig sind auch hier wie­der die Imports, ohne die wir kei­nen Zugriff auf die RMI-Klas­sen von Java hät­ten. Theo­re­tisch soll­te es auch genü­gen, java.rmi.* zu impor­tie­ren. Hier gehen wir etwas expli­zi­ter vor. In Zei­le 10 imple­men­tie­ren wir das Inter­face ServerInterface.java, außer­dem exten­den wir Uni­ca­stRe­mo­te­Ob­ject, wel­ches die Kom­mu­ni­ka­ti­on via Remo­te über­haupt erst ermög­licht. Über die Kom­men­ta­re im Code soll­te der Groß­teil eigent­lich klar sein. Näher erläu­tern möch­te ich an die­ser Stel­le noch die Zei­len 28 und 35:

In Zei­le 28 mel­den wir unse­re Ser­ver­ap­pli­ka­ti­on an der so genann­ten Regis­try an. Die dafür not­wen­di­gen Metho­den ste­hen im Packa­ge java.rmi.registry. zur Ver­fü­gung und wer­den für den hin­ter RMI arbei­ten­den Namens­dienst benö­tigt. Der über­ge­be­ne Port ist frei wähl­bar, muss aber im öffent­li­chen Bereich lie­gen, also darf Port 1000 und grö­ßer ver­wen­det wer­den. Wird kein Port expli­zit gesetzt, läuft der Ser­ver auf Port 1099 und nimmt dort Anfra­gen von Cli­ents ent­ge­gen. In Zei­le 35 ver­wen­den wir die­sen Namens­dienst und geben unse­rem Ser­ver einen kon­kre­ten Namen, über den der Cli­ent eine Ver­bin­dung zu die­sem auf­bau­en kann. In unse­rem Fall wird die Instanz der Klas­se Ser­ver an den Namen “Ser­ver” gebun­den. Logi­scher­wei­se darf auf einer Maschi­ne jeweils nur eine Instanz mit dem glei­chen Namen exis­tie­ren. Im nach­fol­gen­den sehen wir, wie der Cli­ent nun auf den Ser­ver zugrei­fen und die zur Ver­fü­gung gestell­ten Metho­den auf­ru­fen kann (Remo­te Method Invocation).

package de.ulfklose.rmi.tryouts;

import java.rmi.Naming;

public class Client {

public static void main(String[] args) {
try {
ServerInterface server = (ServerInterface)Naming.lookup("//ip.v4.adresse.hierher/Server"); // Verbindung zu Server aufbauen, Name wird in Server.java definiert
System.out.println("Connection to server established.");
System.out.println("Folgender Wert wurde vom Server erhalten: " + server.getValue()); // Methodenaufruf von Server
}
catch (Exception ex)
{
System.out.println(ex.getMessage());
}
}
}

Die Klas­se Client.java impor­tiert den RMI-Namens­dienst in Zei­le 3. In der Main-Metho­de wird dann eine Instanz des Inter­faces erstellt. Über den Namens­dienst bau­en wir eine Ver­bin­dung zu unse­rem Ser­ver auf. Die­ser kann ent­we­der in einer wei­te­ren vir­tu­el­len Maschi­ne auf der glei­chen phy­si­ka­li­schen Maschi­ne lau­fen oder auf einem ande­ren Rech­ner im erreich­ba­ren Netz­werk. Soll die Kom­mu­ni­ka­ti­on über die Gren­zen des eige­nen Netz­werks erfol­gen, müs­sen even­tu­el­le Fire­walls ent­spre­chend kon­fi­gu­riert wer­den. In Zei­le 11 schluss­end­lich rufen wir die Metho­de getVa­lue() vom Ser­ver auf, die wir im Inter­face defi­niert haben. Beim Auf­ruf der Metho­de wird auf dem Cli­ent der aktu­el­le Wert (in unse­rem Fal­le 3) der Varia­blen “value” mit dem vor­an­ge­stell­ten String (Zei­le 12) aus­ge­ge­ben, der Ser­ver wie­der­um gibt auf sei­ner Kon­so­le den Text “getVa­lue() wur­de auf­ge­ru­fen” aus.

Ja, rich­tig, das war es schon. Jetzt suche ich gera­de nach span­nen­den Sachen, die ich mit die­sen Erkennt­nis­sen noch anstel­len kann 😀 Soll­te jemand eine tol­le Idee haben, immer her damit. Und ich hof­fe, dem einen oder ande­ren eine leicht ver­ständ­li­che Anlei­tung über die Grund­la­gen von RMI unter Java gege­ben zu haben.

Ich habe den kom­plet­ten Quell­code aller drei Klas­sen auch bei attachr.com geparkt, viel­leicht sind die dort bes­ser les­bar, falls jemand hier Pro­ble­me haben sollte:

ServerInterface.java

Server.java

Client.java


3 Antworten zu “Einfache RMI-Anwendung mit Java”

  1. Dan­ke, du hast mir damit das Leben geret­tet. Im gan­zen Netz gibt es kei­nen der das The­ma so gut erkla­ert hat. Ne pas­sen­de Main metho­de (anwen­dung) wae­re noch hilf­reich gewe­sen aber sonst. Nicht schlecht. Noch­mals Dan­ke. Amsel

  2. hm…

    Ich schlie­ße mich dem Dan­ke an. 

    Ich sit­ze hier zwar immer noch, wie der Ochs vorm Ber­ge, aber der Nebel des Unver­ständ­nis­ses hat sich ein klei­nes biss­chen gelich­tet. 🙂
    Es besteht Hoff­nung — viel­leicht *denk*

    LG Michae­la

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht.