Programmieren in Java

Werbung
HOCHSCHULE MUENCHEN
FAKULTÄT FÜR ELEKTROTECHNIK UND INFORMATIONSTECHNIK
FG TECHNISCHE INFORMATIK
V – JV – 800 – 00 – TH – 03
-----------------------------------------------------------------------------------
Programmieren in Java
Kapitel 8
8. Java in verteilten Systemen
8.1.
Socket-basierte Kommunikation
8.2.
Remote Method Invocation (RMI)
FACHHOCHSCHULE MUENCHEN
FACHBEREICH ELEKTROTECHNIK UND INFORMATIONSTECHNIK
FG TECHNISCHE INFORMATIK
V – JV – 801 – 00 – TH – 01
-----------------------------------------------------------------------------------
Grundlegendes zu verteilten Systemen
• Verteilte Systeme
◇ Verteilte Systeme bestehen aus zwei oder mehr unabhängigen aber miteinander verbundenen Rechnern (z.B. über
ein Netzwerk), die zur gemeinsamen Lösung von Aufgaben eingesetzt werden können.
◇ Die gemeinsam zu lösende Aufgabe wird auf mehrere Prozesse aufgeteilt, die auf unterschiedlichen Rechnern laufen.
Verteilte Anwendung
◇ Die an einer verteilten Anwendung beteiligten Prozesse müssen miteinander Informationen austauschen. Die dafür
notwendige Interprozess-Kommunikation über Rechnergrenzen hinweg erfordert die Definition und Einhaltung
bestimmter Schnittstellen und Protokolle.
Derartige Protokolle können auf unterschiedlichen Ebenen (Schichten) eingesetzt werden.
• Client-Server-Modell
◇ Am häufigsten arbeiten verteilte Anwendungen nach dem Client-Server-Modell :
Ein Server-Prozess stellt Dienstleistungen über eine definierte Schnittstelle zur Verfügung. Diese Dienstleistungen
können von Client-Prozessen genutzt werden.
◇ Die Kommunikation zwischen Client und Server folgt dem – asymmetrischen – Request-Response-Prinzip :
Ein Client richtet zu einem beliebigen Zeitpunkt – also asynchron – eine Anfrage (request) an den auf Anfragen wartenden Server. Der Server antwortet (response) i.a. innerhalb einer bestimmten Zeit – also synchron – auf diese Anfrage.
◇ Häufig kann ein Server gleichzeitig zu mehreren Clients Kommunikationsbeziehungen unterhalten (MultithreadServer)
◇ Verteilte Anwendungen, bei denen die beteiligten Prozesse sowohl als Server als auch als Client agieren, arbeiten nach
dem Peer-to-Peer-Modell
◇ Prinzipiell werden zwei Verbindungsarten einer Rechnergrenzen überschreitenden Interprozess-Kommunikation
unterschieden :
▻ verbindungsorientierte Kommunikation :
Zwischen Client und Server wird für die Dauer der Kommunikation eine ständige – virtuelle – Verbindung hergestellt. Diese Verbindung muss aufgebaut werden, bevor die eigentliche Kommunikation stattfinden kann.
Die einzelnen Sendeoperationen benötigen keine expliziten Angaben über die Empfängeradresse.
▻ verbindungslose Kommunikation :
Zwischen Client und Server existiert keine ständige Kommunikationsverbindung. Diese wird vielmehr mit jeder
einzelnen Sendeoperation neu hergestellt.
Jeder Sendeoperation muss die Adresse des Empfängers explizit mitgegeben werden.
• Programmierschnittstellen
◇ Die programmtechnische Implementierung von Client-Server-Kommunikationen kann auf unterschiedlichen Schichten
erfolgen (OSI-Schichten-Modell der Rechnerkommunikation !)
◇ Am weitesten verbreitet sind heute :
▻ Sockets, Programmierschnittstelle der Transportschicht (bzw Vermittlungsschicht)
Sockets definieren den jeweiligen Kommunikations-Endpunkt einer logischen Verbindung zwischen Server und
Client. Sie basieren auf dem für die jeweilige Verbindung eingesetzten Kommunikationsprotokoll-Typ und den
von diesem verwendeten Adress-Angaben. Es gibt unterschiedliche Socket-Typen
Sockets ermöglichen eine bidirektionale Kommunikation (Senden und Empfangen) mittels I/O-Operationen
analog zu Datei- bzw Stream-Zugriffen.
Eine Kommunikation über einen Socket kann erst stattfinden, wenn er an eine lokale Adresse gebunden ist
▻ Prozedur-Fernaufrufe (Remote Procedure Calls), Programmierschnittstelle der Anwendungsschicht
Sie ermöglichen den Aufruf von Unterprogrammen (Funktionen), die sich in einem anderen Prozessraum befinden unter Anwendung der gleichen Semantik wie für den Aufruf lokaler Unterprogramme.
Die Implementierung dieses Konzepts in Java wird Remote Method Invocation (RMI) genannt. RMI erlaubt den
Aufruf von Methoden für Objekte, die sich in einer anderen JVM (i.a. auf einem anderen Rechner) befinden.
FACHHOCHSCHULE MUENCHEN
FACHBEREICH ELEKTROTECHNIK UND INFORMATIONSTECHNIK
FG TECHNISCHE INFORMATIK
V – JV – 811 – 00 – TH – 01
-----------------------------------------------------------------------------------
Socket-basierte Kommunikation in Java (1)
• Prinzip der verbindungsorientierten Socket-Kommunikation
◇ Der Server-Prozess erzeugt einen Socket, den er an eine lokale Adresse (Server-Adresse) bindet.
Art und Aufbau der Adresse hängen von der für die Kommunikation eingesetzten Protokoll-Familie ab.
An diesem Socket wartet der Server auf Verbindungswünsche durch Clients ("Horch"-Socket).
◇ Ein Client-Prozess initiiert eine Verbindung zum Server, in dem er einen Socket erzeugt und über diesen einen
Verbindungswunsch an die Server-Adresse sendet.
◇ Falls der Server-Prozess den Verbindungswunsch akzeptiert, erzeugt er einen neuen Socket, über den dann die eigentliche Kommunikation mit dem Client stattfinden kann ("Kommunikations"-Socket).
◇ Die anschliessende eigentliche Client-Server-Kommunikation erfolgt über die Sockets mittels dateianaloger Schreibund Lese-Operationen
◇ Die Kommunikation wird beendet, wenn der Client-Socket oder/und der "Kommunikations"-Socket des Servers
geschlossen werden.
◇ Ein sequentieller Server kann erst nach Abschluss einer Client-Kommunikation auf weitere Verbindungswünsche
warten.
Bei einem Multi-Thread-Server findet jede Client-Kommunikation in einem seperaten Thread statt.
Ein derartiger Server kann auf weitere Verbindungswünsche unmittelbar nach Erzeugung des Kommunikations-Threads
warten
◇ Prinzipieller Ablauf :
Client
Server
Erzeugung
eines "Horch"-Sockets
Bindung an die Server-Adresse
Erzeugung eines Sockets
Verbindungswunsch
an die Server-Adresse
Verbindungsaufnahme
Warten auf
Verbindungswünsche
durch Clients
Akzeptieren eines
Verbindungswunsches
Erzeugung eines
"Kommunikations"-Sockets
Multi-ThreadMulti-ThreadServer
Server
Kommunikation
Schreib-Operation
Lese-Operation
Lese-Operation
Schreib-Operation
Schliessen
des Sockets
Schliessen des
"Kommunikations"-Sockets
sequentieller Server
FACHHOCHSCHULE MUENCHEN
FAKULTÄT FÜR ELEKTROTECHNIK UND INFORMATIONSTECHNIK
FG TECHNISCHE INFORMATIK
V – JV – 812 – 00 – TH – 03
------------------------------------------------------------------------------------
Socket-basierte Kommunikation in Java (2)
• INET-Sockets
◇ INET-Sockets sind Sockets für die TCP/IP-Protokoll-Familie.
Diese Protokoll-Familie hat derzeit für die Rechnerkommunikation die grösste Bedeutung.
U.a. wird sie im Internet, aber auch in den meisten lokalen Netzen eingesetzt.
◇ Adressen der TCP/IP-Protokoll-Familie (INET-Adressen) bestehen aus zwei Komponenten :
▻ IP-Adresse :
Sie bestimmt den Rechner, auf dem ein Prozess läuft
4 Bytes (IP4-Adresse) bzw 16 Bytes (IP6-Adresse) gross.
▻ Port-Nummer : Sie identifiziert den Prozess (Applikation) auf einem Rechner.
2 Bytes gross : ganze Zahl zwischen 0 und 65535
(0 bis 1023 reserviert für systemnahe Dienste, well-known ports)
◇ Zur besseren Verständlichkeit für den benutzenden Menschen werden IP-Adressen häufig auf Rechner-Namen
(host names) abgebildet.
Die Umsetzung von Rechner-Namen in IP-Adressen erfolgt u.a. durch Domain Name Server (DNS).
◇ Die beiden wichtigsten Protokolle dieser Protokoll-Familie sind :
▻ TCP (Transmission Control Protocol)
▻ UDP (User Datagram Protocol)
◇ TCP ist ein Protokoll für die verbindungsorientierte Kommunikation.
Es arbeitet streambasiert und mit Fehlerkontrolle. Dadurch bietet es Schutz gegen Datenverlust und Übertragungsfehler.
Ausserdem stellt es die Beibehaltung der Daten-Reihenfolge sicher (sequencing). zuverlässiges Protokoll
Sockets für dieses Protokoll werden als Stream-Sockets bezeichnet.
◇ UDP ist ein Protokoll für die verbindungslose Kommunikation.
Es arbeitet paketbasiert (Übertragung unabhängiger Datenpakete == Datagramme) sowie ohne Fehlerkontrolle und
Sequencing. Dadurch sind weder Verlustlosigkeit und Fehlerfreiheit noch die Beibehaltung der Datenreihenfolge
sichergestellt. unzuverlässiges Protokoll. Dafür ist die Übertragungsleistung dieses Protokolls höher.
Sockets für dieses Protokoll werden Datagram-Sockets genannt.
• Unterstützung von INET-Sockets in Java
◇ Die Implementierung von verteilten Anwendungen mittels INET-Sockets werden in Java sehr effizient durch geeignete
Klassen der Standard-Bibliothek unterstützt. Die entsprechenden Klassen befinden sich im Package java.net.
◇ Zur Implementierung von Stream-Sockets existieren die Klassen
▻ ServerSocket : Klasse für "Horch"-Sockets in Server-Prozessen
▻ Socket
: Klasse für "Kommunikations"-Sockets in Client- und Server-Prozessen
◇ Die Implementierung einer verbindungslosen Kommunikation über Datagram-Sockets ermöglichen die Klassen :
▻ DatagramSocket : Klasse für Datagramm-Sockets
▻ DatagramPacket : Klasse zur Beschreibung der zu übertragenen Datenpakete
◇ Socket-Adressen werden repräsentiert durch
▻ SocketAddress
: abstrakte Basisklasse für Socket-Adressen, keine konkrete Protokollbindung
▻ InetSocketAddress : konkrete Klasse für Adressen der TCP/IP-Protokoll-Familie (INET-Adresse)
◇ Zur Repräsentation von IP-Adressen existieren die Klassen :
▻ InetAddress : Darstellung sowohl von IP4-Adressen (4-Bytes) als auch IP6-Adressen (16 Bytes)
▻ Inet4Address : Darstellung von IP4-Adressen (abgeleitet von InetAddress)
▻ Inet6Address : Darstellung von IP6-Adressen (abgeleitet von InetAddress)
◇ Zur Repräsentation von Internet-Resourcen referierenden URLs (Uniform Resource Locator) dient die Klasse
▻ URL
◇ Über die o.a. Klassen hinaus umfasst das Package java.net noch eine Reihe weiterer Klassen.
FACHHOCHSCHULE MUENCHEN
FAKULTÄT FÜR ELEKTROTECHNIK UND INFORMATIONSTECHNIK
FG TECHNISCHE INFORMATIK
V – JV – 813 – 00 – TH – 03
------------------------------------------------------------------------------------
Socket-basierte Kommunikation in Java (3)
• Die Klasse InetAddress
◇ Enthalten im Package java.net.
◇ Objekte dieser Klasse repräsentieren IP-Adressen
Über Variable dieses Typs werden tatsächlich Inet4Address-Objekte (für IP4-Adressen (4-Bytes)) bzw
Inet6Address-Objekte (für IP6-Adressen (16 Bytes)) referiert.
Die Klasse InetAddress stellt ein gemeinsames Verwendungsinterface für beide Arten von IP-Adressen zur
Verfügung
◇ Die Klasse besitzt keine öffentlichen Konstruktoren.
Zur Objekterzeugung existieren statische Memberfunktionen. Diesen kann entweder die IP-Adresse (als Byte-Array
oder als String in dotted decimal notation) oder (gegebenenfalls und) der Rechnername übergeben werden.
Bei alleiniger Übergabe des Rechnernamens wird zur Ermittlung der IP-Adresse die im System installierte Methode zur
Namensauflösung (address resolution) verwendet.
Ist eine übergebene IP-Adresse dem Format nach ungültig oder schlägt die Namensauflösung fehl wird von den
Erzeugungsmethoden eine UnknownHostException (abgeleitet von IOException) geworfen.
◇ Neben der IP-Adresse enthalten InetAddress-Objekte gegebenenfalls auch den zugehörigen Rechnernamen.
Dies ist dann der Fall, wenn der Name bei der Objekterzeugung verwendet wurde oder eine inverse Namensauflösung
(reverse host name resolution) vorgenommen wurde.
◇ Die Klasse InetAddress verwaltet einen Cache, in dem erfolgreiche und nicht erfolgreiche Namensauflösungen
abgelegt werden.
◇ Es existieren u.a. Instanz-Memberfunktionen, die die gespeicherte IP-Adresse bzw den Rechnernamen zurückliefern.
◇ Statische Memberfunktion der Klasse InetAddress zur Objekterzeugung (Auswahl)
public static
InetAddress getByAddress(byte[] addr)
throws UnknownHostException
Erzeugung eines InetAddress-Objekts (genauer :
eines Inet4Address- bzw Inet6AddressObjekts) mit der durch addr gegebenen IP-Adresse.
Der Parameter addr muss die Address-Bytes in
Network Byte Order (big endian) enthalten
public static
InetAddress getByName(String host)
throws UnknownHostException
Erzeugung eines InetAddress-Objekts (genauer :
eines Inet4Address- bzw Inet6AddressObjekts) mit der durch Namensauflösung des Rechnernamens host ermittelten IP-Adresse.
Der Parameter host kann auch direkt die IP-Adresse
in Stringdarstellung (dotted decimal notation) enthalten
In diesem Fall entfällt eine Namensauflösung
◇ Instanz-Memberfunktion der Klasse InetAddress (Auswahl)
public byte[] getAddress()
Rückgabe der IP-Adresse als Byte-Array (in Network Byte Order)
public String getHostAddress() Rückgabe der IP-Adresse als String in dotted decimal notation
public String getHostName()
Rückgabe des Rechnernamens falls dieser im Objekt gespeichert ist
oder durch inverse Namensauflösung ermittelt werden kann.
Ist ein Security-Manager installiert, so wird bei erforderlicher inverser
Namensauflösung dieser befragt, ob die Operation zulässig ist
Ist die inverse Namensauflösung unzulässig oder kann der Rechnername nicht ermittelt werden, wird die IP-Adresse als String in dotted
decimal notation zurückgegeben.
HOCHSCHULE MUENCHEN
FAKULTÄT FÜR ELEKTROTECHNIK UND INFORMATIONSTECHNIK
FG TECHNISCHE INFORMATIK
V – JV – 814 – 00 – TH – 04
------------------------------------------------------------------------------------
Socket-basierte Kommunikation in Java (4)
• Die abstrakte Klasse SocketAddress
◇ Enthalten im Package java.net.
◇ Diese Klasse repräsentiert generische – an kein konkretes Protokoll gebundene – Socket-Adressen.
◇ Variable dieses Typs müssen immer Objekte einer konkreten von SocketAddress abgeleiteten Klasse referieren.
Objekte einer derartigen Klasse repräsentieren an jeweils ein konkretes Protokoll gebundene Socket-Adressen.
Z. Zt. existiert in der Java-Standard-Bibliothek lediglich die abgeleitete Klasse InetSocketAddress (für
Adressen der TCP/IP-Protokoll-Familie)
◇ Die Klasse wird u.a. als Typangabe (Parameter- und Rückgabetyp) in Methoden der Klassen Socket und
ServerSocket verwendet.
• Die Klasse InetSocketAddress
◇ Enthalten im Package java.net.
◇ Objekte dieser Klasse repräsentieren Adressen der TCP/IP-Protokoll-Familie (INET-Adressen)
Sie enthalten eine IP-Adresse und eine Port-Nummer.
◇ Bei der Objekterzeugung sind dem Konstruktor die IP-Adresse (als InetAddress-Objekt) und die Port-Nummer
zu übergeben.
Einem alternativen Konstruktor kann statt der IP-Adresse auch der Rechnername übergeben werden. In diesem Fall
wird eine Namensauflösung versucht. Bei Fehlschlag derselben wird der Name im Objekt gespeichert. Das Objekt
repräsentiert dann eine nichtaufgelöste Adresse (unresolved address). Diese kann beispielsweise bei Verbindungsaufnahme über einen Proxy verwendet werden.
◇ Die Klasse InetSocketAddress besitzt Memberfunktionen, mit denen die Komponenten einer von einem
Objekt repräsentierten Adresse ermittelt werden können.
◇ Konstruktoren der Klasse InetSocketAddress
public InetSocketAddress(InetAddress addr,
int port)
Erzeugung einer INET-Adresse aus der IP-Adresse
addr und der Port-Nr port
public InetSocketAddress(int port)
Erzeugung einer INET-Adresse aus der IP-Adresse
0.0.0.0 (wildcard) und der Port-Nr port
public
InetSocketAddress(String host, int port)
Erzeugung einer INET-Adresse aus der durch
Namensauflösung von host ermittelten IP-Adresse
und der Port-Nr port
◇ Memberfunktionen der Klasse InetSocketAddress (Auswahl)
public final InetAddress getAddress()
Rückgabe der IP-Adresse (als InetAddress-Objekt)
public final int getPort()
Rückgabe der Port-Nummer
public final String getHostName()
Rückgabe des Rechnernamens
public final boolean isUnresolved()
Überprüfung, ob der Rechnername aufgelöst werden
konnte
Rückgabe von true, wenn Auflösung nicht möglich war
Rückgabe von false, wenn Auflösung möglich war
FACHHOCHSCHULE MUENCHEN
FACHBEREICH ELEKTROTECHNIK UND INFORMATIONSTECHNIK
FG TECHNISCHE INFORMATIK
V – JV – 815 – 00 – TH – 01
-----------------------------------------------------------------------------------
Socket-basierte Kommunikation in Java (5)
• Die Klasse Socket
◇ Enthalten im Package java.net.
◇ Objekte dieser Klasse implementieren TCP-"Kommunikations-Sockets".
◇ Client-seitige Sockets bauen üblicherweise bei ihrer Erzeugung eine Verbindung zu einem Server auf.
Hierfür muss ihrem Konstruktor die IP-Adresse und die Port-Nummer der Server-Applikation übergeben werden.
Dadurch werden sie auch automatisch an eine geeignete lokale Adresse gebunden.
Falls ein Security-Manager installiert ist, überprüft dieser die Zulässigkeit der gewünschten Verbindung.
Bei Unzulässigkeit wird eine SecurityException geworfen.
Alternativ kann auch ein unverbundener Socket erzeugt werden (parameterloser Konstruktor).
Ein derartiger Socket ist dann auch an keine lokale Adresse gebunden.
Ein explizites Binden an eine lokale Adresse ist mit der Memberfunktion bind(...) möglich.
Der spätere Aufbau einer Server-Verbindung sowie gegebenenfalls die implizite Bindung an eine lokale Adresse
kann mittels der Methode connect(...) erfolgen.
◇ Server-seitige Sockets werden beim Akzeptieren eines Client-Verbindungswunsches durch den "Horch-Socket" erzeugt.
◇ Zur Kommunikation stellen Socket-Objekte jeweils ein InputStream- und ein OutputStream-Objekt
zur Verfügung dateiartige Lese- und Schreib-Operationen.
◇ Nach Beendigung der Kommunikation sollten die Stream-Objekte (zuerst) und das Socket-Objekt geschlossen
werden.
◇ Viele Memberfunktionen (und Konstruktoren) der Klasse Socket können Exceptions verschiedenen Typs werfen
(s. API-Dokumentation)
◇ Konstruktoren der Klasse Socket (Auswahl)
public Socket()
Erzeugung eines unverbundenen Sockets
Der Socket ist auch an keine lokale Adresse gebunden
public Socket(String host, int port)
throws UnknownHostException,
IOException
Erzeugung eines Sockets, der mit der durch host (Rechnername oder IP-Adr. als String) und port definierten ServerAdresse verbunden ist.
Der Socket wird an eine geeignete lokale Adresse gebunden
public Socket(InetAddress adr,
int port)
throws IOException
Erzeugung eines Sockets, der mit der durch adr und
und port definierten Server-Adresse verbunden ist
Der Socket wird an eine geeignete lokale Adresse gebunden
◇ Memberfunktionen der Klasse Socket (Auswahl)
public void bind(SocketAddress adr)
throws IOException
Binden des Sockets an die lokale Socket-Adresse adr
(bei der Adresse muss es sich um eine INET-Adr. handeln)
public void connect(SocketAddress adr) Aufbau einer Verbindung zum Server mit der Adresse adr
throws IOException
(bei der Adresse muss es sich um eine INET-Adr. handeln)
public InputStream getInputStream()
throws IOException
Rückgabe eines InputStream-Objekts, mit dem aus
dem Socket gelesen (empfangen) werden kann
public OutputStream getOutputStream()
throws IOException
Rückgabe eines OutputStream-Objekts, mit dem in
den Socket geschrieben (gesendet) werden kann
public void close() throws IOException Schliessen des Sockets
Memberfunktionen zum Ermitteln der lokalen sowie der verbundenen (entfernten) Adresse, sowohl als INETAdresse (SocketAddress-Objekt) als auch getrennt für IP-Adresse und Port-Nr), s. API-Dokumentation
FACHHOCHSCHULE MUENCHEN
FACHBEREICH ELEKTROTECHNIK UND INFORMATIONSTECHNIK
FG TECHNISCHE INFORMATIK
V – JV – 816 – 00 – TH – 01
-----------------------------------------------------------------------------------
Socket-basierte Kommunikation in Java (6)
• Die Klasse ServerSocket
◇ Enthalten im Package java.net.
◇ Objekte dieser Klasse implementieren TCP-"Horch-Sockets" (Server-Sockets).
◇ Üblicherweise wird ein Server-Socket gleich bei seiner Erzeugung an die lokale Adresse gebunden, an der er auf
Verbindungswünsche warten soll.
Da die IP-Adresse i.a. bekannt ist, muss dem Konstruktor normalerweise nur die Port-Nr übergeben werden.
Alternativ kann dem Konstruktor zusätzlich noch die maximale Grösse der Warteschlange für anstehende Verbindungswünsche übergeben werden (backlog). Ohne diese Angabe wird hierfür der Defaultwert 50 verwendet.
Bei voller Warteschlange werden weitere Verbindungswünsche zurückgewiesen.
Es existiert auch ein Konstruktor, dem zusätzlich eine IP-Adresse (als InetAddress-Objekt) übergeben werden
kann. Dies ermöglicht für Server-Prozesse, die sich auf einem über mehrere IP-Adressen verfügenden Rechner befinden,
die Festlegung einer bestimmten Horch-Adresse .
◇ Alternativ kann auch ein Socket erzeugt werden, der an keine lokale Adresse gebunden ist (parameterloser Konstruktor).
In diesem Fall ist ein späteres Binden an eine lokale Adresse mit der Memberfunktion bind(...) möglich.
◇ Falls ein Security-Manager installiert ist, überprüft dieser sowohl in den Konstruktoren als auch in der Methode
bind(..), ob an der lokalen Adresse ein anschliessendes Warten ("Horchen") auf Verbindungswünsche zulässig ist.
Bei Unzulässigkeit wird eine SecurityException geworfen.
◇ Durch Aufruf der Methode accept() wird ein ServerSocket in den blockierenden Wartezustand versetzt, in dem
er auf Verbindungswünsche durch Clients wartet ("Horch-Zustand").
Für einen akzeptierten Verbindungswunsch erzeugt accept() einen "Kommunikations-Socket". Dieser Socket
ist an ein neues Port gebunden. Dies ermöglicht einem Multi-Thread-Server (Server, bei dem die Kommunikation mit
einem Client jeweils in einem eigenen Thread stattfindet) sofort nach dem Akzeptieren eines Verbindungswunsches
an dem "Horch"-Port auf weitere Verbindungswünsche zu warten.
Falls ein Security-Manager installiert ist, überprüft dieser ob die Erzeugung des vorgesehenen "KommunikationsSockets" zulässig ist. Bei Unzulässigkeit wird eine SecurityException geworfen.
◇ Auch ein ServerSocket-Objekt sollte geschlossen werden, wenn es nicht mehr benötigt wird
◇ Viele Memberfunktionen (und Konstruktoren) der Klasse ServerSocket können Exceptions verschiedenen Typs
werfen (s. API-Dokumentation)
◇ Konstruktoren der Klasse ServerSocket (Auswahl)
public ServerSocket()
throws IOException
Erzeugung eines an keine lokale Adresse gebundenen Sockets
public ServerSocket(int port) Erzeugung eines Server-Sockets, der an die IP-Adresse 0.0.0.0
throws IOException
(wildcard) und die Port-Nr. port gebunden ist.
Herstellung der Bereitschaft, auf Verbindungswünsche zu warten
Für port==0 kann auf allen Ports gewartet werden.
Die maximale Grösse der Warteschlange wird auf 50 gesetzt
◇ Memberfunktionen der Klasse ServerSocket (Auswahl)
public void bind(SocketAddress adr)
throws IOException
Binden des Sockets an die lokale Socket-Adresse adr
(bei der Adresse muss es sich um eine INET-Adr. handeln)
public Socket accept()
throws IOException
Warten auf Verbindungswünsche von Clients. Bei Akzeptieren Erzeugung eines "Kommunikations-Sockets"
public void close() throws IOException Schliessen des Sockets
Memberfunktionen zum Ermitteln der lokalen Adresse, sowohl als INET-Adresse (SocketAddress-Objekt) als
auch getrennt für IP-Adresse und Port-Nr), s. API-Dokumentation
FACHHOCHSCHULE MUENCHEN
FACHBEREICH ELEKTROTECHNIK UND INFORMATIONSTECHNIK
FG TECHNISCHE INFORMATIK
V – JV – 817 – 00 – TH – 01
-----------------------------------------------------------------------------------
Kommunikation über INET-Stream-Sockets in Java
• Prinzipielles Realisierungsgerüst des Servers
1. Erzeugung eines ServerSocket-Objekts
Binden des Sockets an ein Port
ServerSocket srvsk = new ServerSocket(port);
2. Warten auf Verbindungswünsche durch
Clients mittels accept(), damit
Erzeugung eines Socket-Objektes
(i.a. in einer Schleife)
Socket comsk = null;
while ((comsk=srvsk.accept())!=null)
{
3. Kommunikation mit dem Client über das
Socket-Objekt
▻ Ermittlung der vom Socket-Objekt
bereitgestellten Stream-Objekte
InputStream is = comsk.getInputStream();
OutputStream os = comsk.getOutputStream();
▻ Erzeugung der für die Kommunikation
// zum Beispiel :
tatsächlich einzusetzenden Stream-Objekte DataInputStream dis =new DataInputStream(is);
(Objekte von Stream-Filter-Klassen)
DataOutputStream dos=new DataOutputStream(os);
▻ Kommunikation mittels
Lese- und Schreiboperationen
über die Stream-Objekte
// zum Beispiel :
str = dis.readUTF();
dos.writeUTF(str);
▻ nach Beendigung der Kommunikation
Schliessen der Stream-Objekte;
dis.close();
dos.close();
4. Schliessen des Socket-Objektes
comsk.close();
}
• Prinzipielles Realisierungsgerüst des Clients
1. Erzeugung eines Socket-Objektes
Socket sock = new Socket(name, port);
Festlegung des Servers (Name oder IP-Adresse)
und des Ports Verbindungswunsch an Server
2. Kommunikation mit dem Server über das
Socket-Objekt
▻ Ermittlung der vom Socket-Objekt
bereitgestellten Stream-Objekte
OutputStream os = sock.getOutputStream();
InputStream is = sock.getInputStream();
▻ Erzeugung der für die Kommunikation
// zum Beispiel :
tatsächlich einzusetzenden Stream-Objekte DataOutputStream dos=new DataOutputStream(os);
(Objekte von Stream-Filter-Klassen)
DataInputStream dis =new DataInputStream(is);
▻ Kommunikation mittels
Schreib- und Leseoperationen
über die Stream-Objekte
// zum Beispiel :
dos.writeUTF(str);
str = dis.readUTF();
▻ nach Beendigung der Kommunikation
Schliessen der Stream-Objekte;
dis.close();
dos.close();
3. Schliessen des Socket-Objektes
sock.close();
FACHHOCHSCHULE MUENCHEN
FAKULTÄT FÜR ELEKTROTECHNIK UND INFORMATIONSTECHNIK
FG TECHNISCHE INFORMATIK
V – JV – 818 – 01 – TH – 02
------------------------------------------------------------------------------------
Demonstrationsbeispiel zur Kommunikation über INET-Stream-Sockets in Java (1)
• Zu lösende Aufgabe : Filterung von Text
◇ Der zu filternde Text wird in einem Client-Programm zeilenweise von der Standard-Eingabe eingelesen
und über eine INET-Stream-Socket-Verbindung zu einem Server-Programm gesendet.
Der Name des Server-Rechners und die Port-Nr des Server-Programms können durch Kommandozeilen-Parameter
festgelegt werden. Falls das nicht erfolgt : Verwendung von Defaults.
◇ Das Server-Programm filtert die erhaltenen Zeilen-Strings mittels eines Filter-Objektes und sendet anschliessend
die gefilterten Strings über die INET-Stream-Socket-Verbindung zum Client zurück.
Die Port-Nr des Server-Programms kann durch einen Kommandozeilen-Parameter festgelegt werden.
Falls das nicht erfolgt, wird eine Default-Port-Nr verwendet.
◇ Das Client-Programm gibt die erhaltenen gefilterten Zeilen-Strings in die Standard-Ausgabe aus.
◇ Die Art der Filterung wird durch die Klasse des vom Server-Programm eingesetzten Filter-Objekts festgelegt.
Diese muss das Interface TextFilter implementieren.
Hier : Klasse UpcaseFilter (Umwandlung aller Buchstaben in Gross-Buchstaben)
• Quelldatei mit Definition eines Interfaces für Text-Filter (TextFilter.java)
// TextFilter.java
// Definition eines Interfaces fuer Klassen zur TextFilterung
public interface TextFilter
{
public String filterString(String str);
}
• Beispiel einer Text-Filter-Klasse : Quelldatei UpcaseFilter.java
// UpcaseFilter.java
// Klasse zur Filterung von Strings : Umwandlung aller Buchstaben in Gross-Buchstaben
// Implementierung des Interfaces TextFilter
public class UpcaseFilter implements TextFilter
{
public String filterString(String str)
{
return str.toUpperCase();
}
}
FACHHOCHSCHULE MUENCHEN
FAKULTÄT FÜR ELEKTROTECHNIK UND INFORMATIONSTECHNIK
FG TECHNISCHE INFORMATIK
V – JV – 818 – 02 – TH – 02
------------------------------------------------------------------------------------
Demonstrationsbeispiel zur Kommunikation über INET-Stream-Sockets in Java (2)
• Quelldatei mit Klasse für Serverprogramm (FilterServer.java)
// FilterServer.java
// Start-und Steuer-Klasse eines Servers zum Filtern von Strings
import java.net.*;
import java.io.*;
public class FilterServer
{
static final int DEF_PORT = 60290;
public static void main(String[] args) throws IOException
{
int port = DEF_PORT;
if (args.length>0)
port=Integer.parseInt(args[0]);
PrintStream stdout = System.out;
ServerSocket servsock = new ServerSocket(port);
stdout.println("FilterServer");
stdout.println("Lokale Adresse : " + servsock.getInetAddress());
stdout.println("Lokales Port
: " + servsock.getLocalPort() + '\n');
Socket comsock = null;
TextFilter fil = new UpcaseFilter();
while ((comsock=servsock.accept())!=null)
{ stdout.print("Verbindung zu : ");
stdout.print(comsock.getInetAddress());
stdout.println(" (Port : " + comsock.getPort() +")");
DataInputStream in
= new DataInputStream(comsock.getInputStream());
DataOutputStream out = new DataOutputStream(comsock.getOutputStream());
String line = null;
boolean goon = true;
while (goon)
{ try
{ line = in.readUTF();
line = fil.filterString(line);
out.writeUTF(line);
}
catch (EOFException ex)
{ stdout.println("Verbindung geschlossen");
goon = false;
}
catch (IOException ex)
{ stdout.println(ex.getMessage());
goon = false;
}
}
in.close();
out.close();
comsock.close();
}
servsock.close();
}
}
FACHHOCHSCHULE MUENCHEN
FAKULTÄT FÜR ELEKTROTECHNIK UND INFORMATIONSTECHNIK
FG TECHNISCHE INFORMATIK
V – JV – 818 – 03 – TH – 02
------------------------------------------------------------------------------------
Demonstrationsbeispiel zur Kommunikation über INET-Stream-Sockets in Java (3)
• Quelldatei mit Klasse für Clientprogramm (FilterClient.java)
// FilterClient.java
// Filterung von Strings, die ueber die Standardeingabe eingegeben werden
// Demonstrationsbeispiel zur Socket-Kommunikation
import java.io.*;
import java.net.*;
public class FilterClient
{
static final String DEF_HOST = "localhost";
static final int DEF_PORT = 60290;
public static void main(String[] args) throws IOException
{
String host = DEF_HOST;
int port = DEF_PORT;
switch(args.length)
{ case 2 : port = Integer.parseInt(args[1]);
case 1 : host = args[0];
break;
}
PrintStream stdout = System.out;
BufferedReader stdin = new BufferedReader(new InputStreamReader(System.in));
Socket sock = new Socket(host, port);
DataInputStream in
= new DataInputStream(sock.getInputStream());
DataOutputStream out = new DataOutputStream(sock.getOutputStream());
String line;
stdout.print("Eingabe ? ");
while ((line=stdin.readLine())!=null)
{ out.writeUTF(line);
line=in.readUTF();
stdout.println("Ausgabe : " + line);
stdout.print("Eingabe ? ");
}
in.close();
out.close();
sock.close();
}
}
FACHHOCHSCHULE MUENCHEN
FACHBEREICH ELEKTROTECHNIK UND INFORMATIONSTECHNIK
FG TECHNISCHE INFORMATIK
V – JV – 821 – 00 – TH – 01
-----------------------------------------------------------------------------------
Remote Method Invocation (RMI) von Java - Allgemeines
• Konzept von RMI
◇ Ein objektorientiertes System besteht aus einer Ansammlung von Objekten, die miteinander in Kommunikationsbeziehungen stehen.
Jede Kommunikationsbeziehung zwischen Objekten kann als Client-Server-Beziehung aufgefasst werden :
Ein Server-Objekt stellt Dienstleistungen zur Verfügung, die von Client-Objekten durch den Aufruf von Methoden
des Server-Objekts (= Senden von Botschaften an das Server-Objekt) genutzt werden können
◇ Remote Method Invocation (RMI) realisiert eine Übertragung des Konzepts des Prozedur-Fernaufrufs (Remote
Procedure Call, RPC) auf eine objektorientierte Umgebung.
◇ RMI erlaubt den Aufruf von Methoden für Objekte, die sich in anderen virtuellen Maschinen befinden, einschliesslich
solcher virtueller Maschinen, die auf anderen Rechnern laufen.
Kommunikation zwischen Objekten über Rechnergrenzen hinweg verteilte Objekte
◇ RMI ist die Java-spezifische Implementierung eines Systems für verteilte Objekte
"Natürliche" Integration des verteilten Objekt-Modells in die Sprache Java unter Ausnutzung ihrer Konzepte und
Beibehaltung ihrer Objekt-Semantik
Ein entfernter Methodenaufruf sieht wie ein normaler lokaler Methodenaufruf aus
(transparenter entfernter Methodenaufruf)
◇ Bestandteil des Java-API (ab JDK 1.1, modifiziert und erweitert in JDK 1.2)
• Weitere wesentliche Eigenschaften von RMI
◇ Anwendungen stehen zwei Mechanismen zur Erlangung von Referenzen auf entfernte Objekte zur Verfügung :
▻ Nachfragen bei einem RMI-eigenen Namensdienst (rmiregistry)
▻ Übergabe als Parameter und/oder Rückgabewerte von entfernten Funktionsaufrufen
◇ Die eigentliche Kommunikation zwischen verteilten Objekten wird vom RMI-Laufzeitsystem unter Einsatz von
Sockets durchgeführt. Einzelheiten bleiben der eigentlichen Anwendung (und ihrem Programmierer) aber verborgen.
◇ RMI ermöglicht die Übergabe von Objekten als Parameter und Rückgabewerte
Das RMI-Laufzeitsystem stellt die notwendigen Mechanismen zur Übertragung von Objekt-Daten und -Code zur
Verfügung ( Kopieren von Objekten)
Diese beruhen auf
▻ dem Java-Konzept der Objekt-Serialisierung (object serialization)
▻ sowie der Java-Eigenschaft des dynamischen Ladens von Code (dynamic code downloading)
Erzeugung von Objekten, deren Klassen-Implementierung (Java-Byte-Code) lokal nicht verfügbar ist
◇ Das dynamische Laden von Code ermöglicht die dynamische Änderung des Verhaltens von Server und/oder Client
◇ Unterstützung von Callbacks vom Server zum Client
Übergabe von Referenzen auf – im Client vorhandene – entfernte Objekte als Parameter im entfernten Methodenaufruf.
◇ Verteilte Garbage Collection
Einbeziehung von entfernten Objekten in den Garbage Collection Mechanismus von Java
RMI stellt sicher, daß dann und nur dann entfernte Objekte (remote objects) vernichtet werden, wenn weder eine lokale
noch eine entfernte Referenz auf das jeweilige Objekt existiert.
◇ Einbettung in die Sicherheitsmechanismen der Java-Plattform
Verwendung von Security-Manager, Class Loader und Policy Files zur Überprüfung der Zulässigkeit des Ladens
von entferntem Code und des Ausführens von Code (Resourcenzugriff)
◇ Flexibilität und Erweiterbarkeit, z.B.
▻ Implementierung unterschiedlicher Referenz-Semantiken für entfernte (Server-) Objekte
(z.Zt im Standard-API implementiert : UnicastRemoteObject und Activatable )
▻ Einsatz unterschiedlicher Socket-Typen in der Transportschicht von RMI (Ersatz des standardmäßig verwendeten
Socket-Typs (TCP-Protokoll) durch SSL-Sockets oder selbstdefinierte Socket-Typen)
FACHHOCHSCHULE MUENCHEN
FAKULTÄT ELEKTROTECHNIK UND INFORMATIONSTECHNIK
FG TECHNISCHE INFORMATIK
V – JV – 822 – 01 – TH – 02
-----------------------------------------------------------------------------------
Remote Method Invocation (RMI) von Java – Funktionsweise (1)
• RMI –Architektur
◇ Das RMI-System besteht aus drei Schichten :
▻ Stub-/Skeleton-Schicht
▻ RMI-Referenz-Schicht
▻ RMI-Transport-Schicht
Client-Objekt
Server-Objekt
Stub
Skeleton
RMI-Referenz-Schicht
RMI-Referenz-Schicht
RMI-Tranport-Schicht
RMI-Tranport-Schicht
RMILaufzeitSystem
◇ Die Stub-/Skeleton-Schicht bildet die Schnittstelle zwischen den Bestandteilen der verteilten Applikation
(Client-Objekt und Server-Objekt) und dem restlichen RMI-System (RMI-Laufzeitsystem).
Der Stub ist ein Stellvertreter-Objekt (Proxy) des Server-Objekts auf der Clientseite, der die gleiche MethodenAufruf-Schnittstelle wie das Server-Objekt anbietet.
Er nimmt die RMI-Aufrufe des Clients entgegen, wandelt die Methoden-Aufruf-Parameter mittels Objekt-Serialisierung in serielle Byte-Streams um (marshalling) und leitet diese zusammen mit den für den Aufruf der Serverfunktion
benötigten Informationen (Identifikation des Ziel-Objekts und der aufzurufenden Methode) an die RMI-Referenzschicht
weiter
Umgekehrt erhält er von der RMI-Referenzschicht die Rückgabewerte eines RMI-Aufrufs als Byte-Streams, deserialisiert diese (ummarshalling) und reicht sie an das aufrufende Client-Objekt weiter.
Das Skeleton nimmt auf der Serverseite die RMI-Aufrufe von der RMI-Referenzschicht entgegen, deserialisiert die
als Byte-Streams erhaltenen Parameter und ruft mit diesen die eigentlich auszuführende im Server-Objekt implementierte Methode auf. Nach Bendigung dieser Funktion nimmt es deren Rückgabewerte entgegen und leitet sie nach
Serialisierung an die RMI-Referenzschicht weiter.
In früheren Java-Versionen wurde hierfür ein eigenes Skeleton-Objekt eingesetzt.
In neueren Versionen wird die Funktionalität des Skeletons durch einen allgemeinen Verteiler des RMI-Laufzeitsystems ersetzt. Es muss daher kein eigenes Skeleton-Objekt mehr erzeugt werden.
Der Stub muss dagegen an das jeweilige Server-Objekt angepaßt sein.
Seine Klasse wird aus der Server-Objekt-Klasse mittels eines RMI-Compilers (rmic) generiert.
(Der RMI-Compiler war früher auch zuständig für die Erzeugung der Skeleton-Klasse)
Ab dem JDK 5.0 kann das Stub-Objekt dynamisch zur Laufzeit erzeugt werden. Aufruf von rmic nicht
erforderlich wenn auch der Client-Code mit dem JDK 5.0 erzeugt wurde.
◇ Die RMI-Referenz-Schicht ist für die Lokalisierung des jeweiligen Kommunikationspartners (Server bzw Client)
zuständig. Sie beinhaltet den RMI-Namensdienst (Registry) und verwaltet die Referenzen auf entfernte Objekte.
Unter Berücksichtigung der jeweiligen Referenz-Semantik gibt sie die vom Stub erhaltenen RMI-Aufrufe einschließlich deren Parameter (Byte-Streams) an die RMI-Transportschicht weiter.
Auf der Serverseite nimmt sie die RMI-Aufrufe und deren Parameter von der RMI-Transportschicht entgegen, aktiviert
gegebenenfalls das Server-Objekt und leitet die Aufrufe an das Skeleton weiter.
Analog ist sie an der Übermittlung der Rückgabewerte beteiligt.
◇ In der RMI-Transport-Schicht werden die Kommunikationsverbindungen verwaltet und die eigentliche Kommunikation zwischen verschiedenen Adressräumen (JVMs) abgewickelt.
Üblicherweise werden hierfür Sockets eingesetzt.
FACHHOCHSCHULE MUENCHEN
FACHBEREICH ELEKTROTECHNIK UND INFORMATIONSTECHNIK
FG TECHNISCHE INFORMATIK
V – JV – 822 – 02 – TH – 01
-----------------------------------------------------------------------------------
Remote Method Invocation (RMI) von Java – Funktionsweise (2)
• Übertragung von Parametern und Rückgabewerten
◇ Die Parameter und Rückgabewerte von RMI-Aufrufen werden mittels Objekt-Serialisierung als Byte-Streams
übertragen.
Übertragbare Objekte müssen serialisierbar sein, d.h. das Interface java.io.Serializable implementieren.
◇ einfache Datentypen : Übertragung der Werte (Call by Value)
◇ lokale Objekte (non-remote objects) : Übertragung einer Kopie des Objekts (Call by Copy)
Für Rückgabewerte wird beim Aufrufer ein neues Objekt erzeugt
◇ entfernte Objekte (remote objects) : Übertragung einer Referenz auf das Objekt (Call by Reference)
Die Referenz ist das zum Objekt gehörende Stub-Objekt. (das seinerseits per Kopie übertragen wird)
◇ In dem im Byte-Stream für ein übertragenes Objekt enthaltenen Klassen-Deskriptor ist auch die URL über die der
Klassen-Code (Java Byte Code) zugänglich ist, vermerkt.
Dies ermöglicht es dem empfangenden System, den Klassen-Code dynamisch zu laden, falls er nicht lokal verfügbar
ist. (Dynamic Code Downloading).
Eine derartige Situation kann auftreten, wenn das übertragene Objekt eine Instanz eines Untertyps des deklarierten
Parametertyps ist. Ein Untertyp in diesem Sinn ist entweder eine Klasse, die ein Interface, das als Parametertyp deklariert ist, implementiert oder eine von der Parameterklasse abgeleitete Klasse.
• RMI-Registry
◇ Die RMI-Registry ist ein einfacher Namensdienst, der es Clients ermöglicht, entfernte Objekte über ihren Namen zu
lokalisieren.
◇ Eine RMI-Registry muß lokal auf dem System, das Objekte für RMI-Aufrufe (entfernte Objekte) bereitstellt (RMIServer) existieren.
◇ Üblicherweise wird die RMI-Registry in einer eigenen JVM als Hintergrundprozeß gestartet.
Defaultmäßig "horcht" sie auf Port 1099.
Sie kann aber auch mit einer anderen Port-Nummer gestartet werden.
Kommando :
[start] rmiregistry [port] (Windows)
rmiregistry [port] &
(Linux)
◇ Ein entferntes Objekt, das über die Registry zugänglich sein soll, muß vom Server-Prozeß der Registry bekannt
gemacht (registriert, "gebunden") werden.
◇ Ein Client, der einen RMI-Aufruf ausführen möchte, benötigt eine Referenz auf das entsprechende (entfernte) ServerObjekt. Diese erhält er durch eine Nachfrage ("lookup") bei der RMI-Registry des Server-Rechners.
Falls für das – über einen Namen referierte – Objekt ein Eintrag vorhanden ist, liefert die Registry sein als Referenz
dienendes Stub-Objekt zurück.
◇ Typischerweise wird die RMI-Registry nur zur Lokalisierung des ersten vom Client referierten entfernten Objekts
verwendet.
Weitere gegebenenfalls benötigte entfernte Objekte können dann über dieses Objekt ermittelt werden (als Parameter
bzw Rückgabewerte von RMI-Aufrufen)
◇ Die Kommunikation mit der RMI-Registry erfolgt üblicherweise über das von der Java-Klasse java.rmi.Naming
bereitgestellte Interface (statische Methoden)
◇ Tatsächlich stellt die RMI-Registry bereits selbst ein besonderes entferntes Objekt dar, zu dem auch mittels RMI, das
durch die Naming-Funktionen gekapselt wird, zugegriffen wird.
2 : Nachfrage
RMI-Registry
1:Registrierung
Client-Objekt
3 : RMI-Aufruf
Server-Objekt
FACHHOCHSCHULE MUENCHEN
FAKULTÄT ELEKTROTECHNIK UND INFORMATIONSTECHNIK
FG TECHNISCHE INFORMATIK
V – JV – 822 – 03 – TH – 02
-----------------------------------------------------------------------------------
Remote Method Invocation (RMI) von Java – Funktionsweise (3)
• Dynamisches Laden von Code (Dynamic Code Downloading)
◇ Eine hervorstechende Eigenschaft von Java ist die Fähigkeit, dynamisch Code von jeder URL in eine laufende
Java Virtual Machine (JVM) zu laden. I.a. wird die URL auf ein anderes physikalisches System verweisen.
Eine JVM kann Code ausführen, der nie auf ihrem eigenen System installiert worden ist.
◇ Diese Fähigkeit wird auch vom RMI-System genutzt :
▻ Zum Laden des Codes für den Stub des Server-Objekts durch den Client (ab dem JDK 5.0 nicht mehr erforderlich).
Die Stub-Klasse muß nicht lokal zur Verfügung stehen
(ab dem JDK 5.0 wird sie lokal beim Client aus dem RMI-Interface erzeugt)
▻ Zum Laden des Codes für als Parameter in oder Rückgabewerte von RMI-Aufrufen übergebene Objekte
(sowohl lokale Objekte als auch entfernte Objekte)
◇ Das dynamische Laden von Code erfordert das Setzen der Property java.rmi.server.codebase in der JVM
des das Objekt bzw die Klasse zur Verfügung stellenden Prozesses :
- bei Stubs von Server-Objekten : in der JVM des RMI-Server-Prozesses, der ein entferntes Objekt registriert
(ab dem JDK 5.0 nicht mehr notwendig)
- bei als Parameter übergebenen Objekten : in der JVM des RMI-Client-Prozesses
- bei Objekten, die von RMI-Aufrufen zurückgegeben werden : in der JVM des Server-Prozesses
Als Wert der codebase-Property ist die URL, von der der Klassen-Code geladen werden kann, anzugeben.
Diese URL kann sich auf ein drittes System beziehen.
◇ Wenn der Server-Prozeß ein entferntes Objekt unter einem Namen bei der RMI-Registry registriert, wird der in der
Server-JVM gesetzte codebase-Wert (URL !) zusammen mit der Objekt-Referenz (Stub-Objekt) gespeichert.
Voraussetzung : Der Code der Stub-Klasse darf nicht über die CLASSPATH-Environment-Variable der JVM der
RMI-Registry erreichbar sein. (gilt nicht ab dem JDK 5.0, da muss die .class-Datei des RMI-Interfaces über die
CLASSPATH-Environment-Variable der JVM der RMI-Registry erreichbar sein)
◇ Der Client-Prozeß erhält auf seine Nachfrage bei der RMI-Registry das Stub-Objekt als Referenz auf das ServerObjekt. Falls er den Stub-Klassen-Code nicht über seine CLASSPATH-Environment-Variable lokal findet, versucht
er bis einschliesslich dem JDK 1.4 den Code von der mit dem Stub-Objekt verbundenen URL (codebase-Wert) zu
laden. (ab dem JDK 5.0 wird der Code lokal aus dem RMI-Interface erzeugt)
Voraussetzung : Der RMI-Client-Prozeß hat einen Security-Manager installiert, der das Laden des Stubs erlaubt
(z.B. RMISecurityManager). In Java 2 (ab JDK 1.2) erfordert dies zusätzlich ein entsprechend konfiguriertes
Security Policy File (Default : Datei .java.policy im Heimat-Verzeichnis des Users)
Anmerkung : Der Security-Manager wird bereits für den Zugriff zur Registry benötigt.
◇ Analog erfolgt das Laden von Klassen-Codes für Objekte, die dem Server-Objekt vom Client-Objekt als Parameter
in RMI-Aufrufen übergeben werden (einschliesslich das Laden aller weiteren von diesen benötigten Objekte).
Das gilt auch für das JDK 5.0 !
Voraussetzungen : Der codebase-Wert im Client-Prozeß ist auf die richtige URL gesetzt und das Server-Objekt
kann den Code nicht lokal über seine CLASSPATH-Environment-Variable finden. Außerdem muß im Server ein
Security-Manager installiert sein.
5. Rückgabe des KlassenCodes des Stub-Objekts
4. u. 5
nicht bei
JDK 5.0
4. Erfragen des
Klassen-Codes
für Stub-Objekt
2. NamensNachfrage
Client-Objekt
myHost
codebase-URL
(http)
RMI-Registry
Server-Prozeß,
der entferntes Objekt
erzeugt
1. Registrierung
des entfernten
Server-Objekts
3. Rückgabe eines
Stub-Objekts
6. RMI-Aufruf
Server-Objekt
java.rmi.server.codebase
=http://myHost/mydir/
FACHHOCHSCHULE MUENCHEN
FAKULTÄT FÜR ELEKTROTECHNIK UND INFORMATIONSTECHNIK
FG TECHNISCHE INFORMATIK
V – JV – 823 – 01 – TH – 02
------------------------------------------------------------------------------------
Java-RMI - Interfaces und Klassen (1)
• RMI-Packages
Das RMI-API von Java wird durch die folgenden Packages zur Verfügung gestellt :
▻ java.rmi
grundlegendes Package
▻ java.rmi.activation
Unterstützung für die RMI Object Activation
▻ java.rmi.dgc
Klassen und Interfaces für die RMI Distributed Garbage Collection
▻ java.rmi.registry
Klassen und Interfaces für die RMI-Registry
▻ java.rmi.server
Klassen und Interfaces zur Unterstützung der Server-Seite von RMI
• Überblick über die wichtigsten Interfaces und Klassen des RMI-API
Für Anwenderprogramme sind vor allem die folgenden Interfaces und Klassen von Bedeutung :
interface
abstract class
class
Remote
RemoteObject
RemoteException
(java.rmi)
(java.rmi.server)
(java.rmi)
abstract class
RemoteServer
(java.rmi.server)
class
class
UnicastRemoteObject
Activatable
(java.rmi.server)
(java.rmi.activation)
class
class
Naming
RMISecurityManager
(java.rmi)
(java.rmi)
FACHHOCHSCHULE MUENCHEN
FAKULTÄT FÜR ELEKTROTECHNIK UND INFORMATIONSTECHNIK
FG TECHNISCHE INFORMATIK
V – JV – 823 – 02 – TH – 03
------------------------------------------------------------------------------------
Java-RMI - Interfaces und Klassen (2)
• Die wichtigsten Interfaces und Klassen des Java-RMI-API - Kurzbeschreibung
◇ interface Remote (Package : java.rmi)
"Basis"-Interface für alle Interfaces, deren Methoden mittels RMI aufrufbar sein sollen.
Alle Klassen, deren Objekte mittels RMI ansprechbar sein sollen, müssen direkt oder indirekt – über abgeleitete
Interfaces – dieses Interface implementieren.
Mittels RMI können nur die Methoden, die in einem von Remote abgeleiteten Interface ( remote interface) spezifiziert sind, aufgerufen werden.
◇ class RemoteObject (Package : java.rmi.Server)
Abstrakte Klasse, die einige Methoden der Klasse java.lang.Object für entfernt nutzbare Objekte (remote
objects) überschreibt und damit die entsprechenden Fähigkeiten für derartige Objekte implementiert.
(spezielle Implementierungen der Methoden hashCode(), equals() und toString())
◇ class RemoteServer (Package : java.rmi.Server)
Abstrakte Superklasse der Klassen für entfernt nutzbare Server-Objekte.
Sie stellt ein gemeinsames Framework zur Unterstützung unterschiedlichster Semantiken für entfernte Referenzen
zur Verfügung, die durch die von ihr abgeleiteten Klassen implementiert werden
Die zur Erzeugung und Exportierung von Objekten an das RMI-Laufzeitsystem benötigten Methoden (Konstruktoren
und gegebenenfalls weitere Methoden) werden durch die von dieser Klasse abgeleiteten Klassen bereitgestellt.
U.a. stellt diese Klasse auch eine statische Methode zum Ermitteln des aufrufenden Client-Rechners zur Verfügung.
◇ class UnicastRemoteObject (Package : java.rmi.Server)
Von der Klasse RemoteServer abgeleitete Klasse für einfache – nicht replizierbare – entfernte Objekte, deren
Referenzen nur gültig sind, solange die Objekte aktiv sind.
Sie stellt die Unterstützung für Punkt-zu-Punkt-Verbindungen zu aktiven Objekten (bezüglich Aufrufe, Parameter,
Rückgabewerte) unter Verwendung von TCP-Sockets bereit
Durch Übergabe eines int-Parameters an den Konstruktor kann die Port-Nummer festgelegt werden.
Wird kein Parameter übergeben, wird vom System ein anonymes Port gewählt.
Eigene Klassen, die diese Referenz-Semantik bereitstellen sollen, müssen – unter Implementierung eines geeigneten
remote interfaces - von dieser Klasse abgeleitet werden.
◇ class Activatable (Package : java.rmi.Activation)
Von der Klasse RemoteServer abgeleitete Klasse für entfernte Objekte, deren Referenzen auch gültig sind,
wenn die Objekte inaktiv und persistent ausgelagert sind Diese Objekte können bei Bedarf wieder aktiviert werden.
Eigene Klassen, die diese Referenz-Semantik bereitstellen sollen, müssen – unter Implementierung eines geeigneten
remote interfaces - von dieser Klasse abgeleitet werden.
◇ class RemoteException (Package : java.rmi)
Superklasse der kommunikationsorientierten Exceptions, die bei RMI auftreten können.
Alle Methoden eines remote interfaces müssen diese Exception weiterreichen können, d.h. in ihrem Funktionskopf
muß eine entsprechende Exception-Spezifikation (throws-Klausel) enthalten sein.
◇ class Naming (Package : java.rmi)
Nicht ableitbare Klasse (final), die statische Methoden zum Zugriff zur RMI-Registry bereitstellt
◇ class RMISecurityManager (Package : java.rmi)
Beispiel eines von RMI-Anwendungen für das dynamische Laden von Code benötigten Security-Managers.
Der RMI Class Loader kann ohne installierten Security-Manager keinen Code von URLs, die auf einen entfernten
Rechner verweisen, laden.
FACHHOCHSCHULE MUENCHEN
FAKULTÄT ELEKTROTECHNIK UND INFORMATIONSTECHNIK
FG TECHNISCHE INFORMATIK
V – JV – 824 – 01 – TH – 02
-----------------------------------------------------------------------------------
Erzeugung einer RMI-Anwendung (1)
• Auszuführende Schritte
▶ Definition eines Interfaces für die RMI-Aufrufe (remote interface)
▶ Erstellung eines Servers (Implementierung des Interfaces und der Server-Start-Funktionalität)
▶ Entwicklung eines Clients, der unter Nutzung dieses Interfaces RMI-Aufrufe ausführt
▶ Erzeugung der Stub-Klasse (ab dem JDK 5.0 nicht mehr erforderlich)
▶ Starten der RMI-Registry auf dem Server-Rechner
▶ Start des Servers und des Clients
• Definition eines Interfaces für die RMI-Aufrufe (remote interface)
◇ Alle Methoden des Server-Objekts, die über RMI aufrufbar sein sollen, sind in einem Interface zu deklarieren
(RMI-Methoden)
◇ Eigenschaften dieses RMI-Interfaces :
► Das Interface muß public deklariert werden
► Das Interface muß von dem Interface java.rmi.Remote abgeleitet sein ( remote interface).
► Jede Methode des Interfaces muß die Exception java.rmi.RemoteException als werfbar deklarieren
(Exception-Deklaration : throws java.rmi.RemoteException)
◇ Die Klasse der RMI-Server-Objekte muß dieses Interface implementieren (RMI-Server-Klasse).
Nur die Methoden der Server-Objekte, die in diesem Interface enthalten sind, sind auch entfernt aufrufbar.
Alle weiteren eventuell vorhandenen Methoden sind nur lokal ansprechbar.
◇ Der Client muß das Stub-Objekt, das er als lokale Referenz auf das entfernte Server-Objekt erhält, immer als eine
Instanz dieses Interfaces referieren .
Der hierfür notwendige Type-Cast ist zulässig, da auch die Stub-Klasse dieses Interface implementiert.
◇ Übersetzung der Java-Quell-Datei (z.B. MyServer.java)
Erzeugung einer Java-Bytecode-Datei (MyServer.class)
• Klassendiagramm für einen einfachen RMI-Server
FACHHOCHSCHULE MUENCHEN
FACHBEREICH ELEKTROTECHNIK UND INFORMATIONSTECHNIK
FG TECHNISCHE INFORMATIK
V – JV – 824 – 02 – TH – 01
-----------------------------------------------------------------------------------
Erzeugung einer RMI-Anwendung (2)
• Erstellung eines Servers
◇ Zur Realisierung eines RMI-Servers werden benötigt :
► Eine das RMI-Interface implementierende Klasse (RMI-Server-Klasse)
► Die Server-Start-Funktionalität.
Häufig wird die Server-Start-Funktionalität durch die main()-Methode der RMI-Server-Klasse realisiert.
Diese main()-Methode kann aber auch in einer anderen – speziell hierfür vorgesehenen - Klasse enthalten sein.
◇ Die RMI-Server-Klasse muß
► wenigstens ein RMI-Interface (remote interface) implementieren
► von einer Unterklasse der Klasse java.rmi.server.RemoteServer abgeleitet sein
► einen Konstruktor definieren, der die Exception java.rmi.RemoteException werfen kann
► alle im implementierenden RMI-Interface enthaltenen Methoden definieren
◇ Die Server-Start-Funktionalität beinhaltet :
▻ Erzeugung und Installation eines Security Managers
▻ Erzeugung eines oder mehrerer RMI-Server-Objekte (Instanzen der RMI-Server-Klasse)
▻ Registrierung wenigstens eines dieser Objekte bei der RMI-Registry
◇ Erzeugung und Installation eines Security-Managers
In jeder JVM, in der Code von anderen Quellen als den durch die CLASSPATH-Environmentvariable festgelegten
geladen werden soll, muß ein Security-Manager installiert sein.
Falls noch kein Security-Manager installiert ist, muß der Server einen installieren – entweder eine Instanz der Klasse
RMISecurityManager oder einer selbstdefinierten Security-Manager Klasse
if (System.getSecurityManager()==null)
{
System.setSecurityManager(new RMISecurityManager());
}
◇ Registrierung eines RMI-Server-Objektes bei der lokalen RMI-Registry
Mittels der statischen Methode rebind() der Klasse Naming :
public static void rebind(String name, Remote obj) throws RemoteException,
MalformedURLException
Parameter : name
obj
Beispiel :
- URL-formatierter String, der das zu registrierende Objekt bezeichnet
- Allgemeine Form : "//host:port-nr/ObjectName".
- Wenn die RMI-Registry auf dem Default-Port 1099 läuft, können die Angabe des Hosts
(host) und der Port-Nr. (port-nr) weggelassen werden, es reicht die Angabe von
"ObjectName".
- "ObjectName" ist ein beliebiger Name unter dem das Objekt registriert werden soll.
Name des Objekts unter dem es angelegt worden ist und im Programm referiert wird.
Naming.rebind("MyServer", serv);
Die von der Methode werfbaren Exceptions müsssen gefangen werden.
◇ Jeder Aufruf einer RMI-Methode erfolgt in einem eigenen Thread.
Ein mittels RMI realisierter Server ist grundsätzlich ein Multithread-Server.
◇ Innerhalb einer RMI-Methode kann der Rechner des aufrufenden Clients mittels der von RemoteServer geerbten
statischen Methode getClientHost() ermittelt werden :
public static String getClientHost() throws ServerNotActiveException
Funktionswert : String-Repräsentation des Client-Rechners
FACHHOCHSCHULE MUENCHEN
FAKULTÄT FÜR ELEKTROTECHNIK UND INFORMATIONSTECHNIK
FG TECHNISCHE INFORMATIK
V – JV – 824 – 03 – TH – 03
------------------------------------------------------------------------------------
Erzeugung einer RMI-Anwendung (3)
• Entwicklung eines Clients
◇ Wesentliche Funktionalität des Clients :
► Erzeugung und Installation eines Security-Managers
► Erfragen einer Referenz auf das entfernte RMI-Server-Objekt bei der RMI-Registry
► Aufruf der RMI-Methoden über die erhaltene Referenz
◇ Die Erzeugung und Installation eines Security Managers erfolgt analog wie beim Server :
if (System.getSecurityManager()==null)
{
System.setSecurityManager(new RMISecurityManager());
}
◇ Erfragen einer Referenz auf das entfernte RMI-Server-Objekt bei der RMI-Registry
Mittels der statischen Methode lookup() der Klasse Naming :
public static Remote lookup(String name) throws NotBoundException,
MalformedURLException,
RemoteException
Parameter : name
- URL-formatierter String, der das zu suchende Objekt bezeichnet
- Allgemeine Form : "//host:port-nr/ObjectName".
- Als Host (host) ist der Rechner (Name oder IP-Adresse) anzugeben, auf dem sich das
gesuchte Objekt und die RMI-Registry befindet.
- Wenn die RMI-Registry auf dem Default-Port 1099 läuft, kann die Angabe der Port-Nr.
(port-nr) weggelassen werden
- "ObjectName" ist der Name des Objekts, unter dem es in der Registry registriert
worden ist.
Die Methode Naming.lookup() erzeugt unter Verwendung von Host und Port-Nr. ein Registry-Stub-Objekt,
über das die Methode lookup() für die Registry mit "ObjectName" als Parameter aufgerufen wird.
Diese gibt – sofern ein Eintrag in der Registry vorhanden ist – ein Stub-Objekt für das gesuchte RMI-Server-Objekt
zurück.
Naming.lookup() gibt dieses Stub-Objekt als Referenz auf das RMI-Server-Objekt an den aufrufenden Client
zurück (als Instanz des Interfaces Remote).
Der Stub-Code wird – sofern er nicht lokal über die CLASSPATH-Environmentvariable gefunden wird – bis zum
JDK 1.4 von der in der Registry für die Stub-Klasse abgelegten (und im Stub-Objekt angegebenen) Codebase geladen.
Ab dem JDK 5.0 wird er lokal beim Client aus dem RMI-Interface erzeugt.
Der Client wandelt den Typ des Stub-Objekts in den Typ des vom RMI-Server-Objekt implementierten RMI-Interfaces um.
◇ Der Client referiert das erhaltene Stub-Objekt als Instanz des vom RMI-Server-Objekt implementierten RMI-Interfaces. Über diese Instanz erfolgt ein Aufruf der RMI-Methoden.
FACHHOCHSCHULE MUENCHEN
FAKULTÄT FÜR ELEKTROTECHNIK UND INFORMATIONSTECHNIK
FG TECHNISCHE INFORMATIK
V – JV – 824 – 04 – TH – 03
------------------------------------------------------------------------------------
Erzeugung einer RMI-Anwendung (4)
• Erzeugung der Stub- (und früher auch Skeleton-)Klassen
◇ Ab dem (und für das) JDK 5.0 wird das Stub-Objekt dynamisch zur Laufzeit erzeugt
keine explizite Erzeugung der Stub-Klasse erforderlich (kein Aufruf von rmic).
◇ Für Vor-JDK-5.0-Anwendungen muss die Stub-Klasse (und gegebenenfalls auch die Skeleton-Klasse) explizit mittels
des RMI-Compilers (Stub-Generators) rmic aus der das RMI-Interface implementierenden RMI-Server-Klasse und
dem RMI-Interface erzeugt werden.
◇ Dem RMI-Compiler ist der voll-qualifizierte Package-Name der als Java-Byte-Code vorliegenden RMI-ServerKlasse als Parameter zu übergeben.
◇ Die den Java-Byte-Code der RMI-Server-Klasse enthaltende Datei (.class-file) sowie die Datei mit dem Java-ByteCode (oder mit dem Quell-Code) des RMI-Interfaces müssen über die CLASSPATH-Environment-Variable erreichbar sein.
◇ Zusätzlich kann beim Aufruf von rmic mit der "-d" Option angegeben werden, in welchem Ausgangs-Directory die erzeugten Java-Byte-Code-Dateien (.class-files) für Stub (und gegebenenfalls Skeleton) abgelegt werden
sollen (Ausgehend von diesem Directory erfolgt die Ablage in einer dem vollqualifizierten Package-Namen entsprechenden Directory-Struktur). Ohne diese Angabe dient das aktuelle Directory als Ausgangs-Directory.
◇ Die von rmic erzeugten Klassen-Dateien für Stub (und gegebenefalls Skeleton) tragen den um _Stub bzw _Skel
ergänzten Hauptnamen der RMI-Server-Klassen-Datei
◇ Beispiel : (ohne Verwendung eines Package-Namens)
rmic –d G:\MyJava\classes\ MyServerImpl
Hierdurch werden die Dateien MyServerImpl_Stub.class und MyServerImpl_Skel.class im
Directory G:\MyJava\classes erzeugt.
• Starten der RMI-Registry
◇ Üblicherweise wird die RMI-Registry als eigener Prozeß (in einer eigenen JVM laufend) auf dem Server-Rechner von
der Kommandozeile aus mit dem Kommando rmiregistry gestartet. Falls die Registry nicht auf dem DefaultPort 1099 arbeiten soll, muß die Port-Nr. beim Aufruf als Parameter angegeben werden.
Beispiel :
rmiregistry
rmiregistry 1248
( Registry läuft auf Port-Nr. 1099)
( Registry läuft auf Port-Nr. 1248)
◇ Alternativ kann die Registry auch lokal für den Server-Prozeß von diesem erzeugt und gestartet werden
(Statische Methode createRegistry() der Klasse LocateRegistry)
◇ Achtung : Bis zum JDK 1.4 gilt : Die .class-Datei der Stub-Klasse(n) darf für die JVM der RMI-Registry nicht
über die CLASSPATH-Environment-Variable erreichbar sein. Beim Start des Servers muss die Codebase, in der
sich die Stub-Klasse befindet, angegeben werden.
Alternative ab dem JDK 5.0 : Der RMI-Registry kann statt der Stubklasse auch die .class-Datei des RMI-Interfaces zur Verfügung gestellt werden – entweder über die Codebase oder durch Bereitstellung einer direkten Zugriffsmöglichket ( .class-Datei des RMI-Interfaces befindet sich im Startverzeichnis der Registry oder die CLASSPATHVariable enthält das Directory der .class-Datei )
• Start des Servers und des Clients
◇ Auf dem Server- und dem Client-Rechner sind jeweils eine JVM mit der jeweiligen Start-Klasse zu starten.
◇ Als Optionen können die Codebase (URL) und die zu verwendende Policy-Datei (Dateipfad) angegeben werden
(Default für die Policy-Datei : .java.policy im Heimat-Verzeichnis des Users)
◇ Beispiel (für Server, kein Package-Name) :
java –Djava.rmi.server.codebase=http://cd2/~thomas/classes/
-Djava.security.policy=my.policy MyServerImpl
FACHHOCHSCHULE MUENCHEN
FACHBEREICH ELEKTROTECHNIK UND INFORMATIONSTECHNIK
FG TECHNISCHE INFORMATIK
V – JV – 825 – 01 – TH – 01
-----------------------------------------------------------------------------------
Einfaches Demonstrationsbeispiel zu RMI in Java (1)
• Zu lösende Aufgabe : Filterung von Text
◇ Lösung der Aufgabe des Demonstrationsbeispiels zur INET-Socket-Kommunikation mittels RMI
◇ Definition eines Remote-Interfaces, das die Methode filterString() deklariert (RMI-Methode).
◇ Das Remote-Interface wird durch eine RMI-Klasse implementiert.
In einem Server-Programm wird ein Objekt dieser Klasse instanziiert ( Remote-Objekt)
◇ Die RMI-Klasse implementiert in ihrer main()-Methode auch die Server Start-Funktionalität.
◇ Der zu filternde Text wird in einem Client-Programm zeilenweise von der Standard-Eingabe eingelesen
Zur Filterung ruft der Client die RMI-Methode filterString() des Remote-Objekts im Server auf.
Der Name des Server-Rechners kann beim Client-Start durch Kommandozeilen-Parameter festgelegt werden.
Falls das nicht erfolgt : Verwendung von Defaults.
◇ Die RMI-Methode des Remote-Objekts des Servers filtert die erhaltenen Zeilen-Strings mittels eines Filter-Objektes
und gibt die gefilterten Strings als Funktionswert der RMI-Methode an den Client zurück.
Das Filter-Objekt wird dem Remote-Objekt bei der Erzeugung im Konstruktor zu übergeben.
◇ Das Client-Programm gibt die erhaltenen gefilterten Zeilen-Strings in die Standard-Ausgabe aus.
◇ Die Art der Filterung wird durch die Klasse des vom Server-Programm eingesetzten Filter-Objekts festgelegt.
Diese muss das Interface TextFilter implementieren. (s. Beispiel zur INET-Socket-Kommunikation)
Hier : Klasse UpcaseFilter (Umwandlung aller Buchstaben in Gross-Buchstaben)
◇ Die RMI-Registry wird auf dem Default-Port 1099 gestartet.
Das Remote-Objekt wird unter dem Namen "TextFilter" in der RMI-Registry registriert
• Quelldatei mit der Definition des Remote-Interfaces (RMITextFilter.java)
// RMITextFilter.java
// Definition eines Remote-Interfaces fuer Klassen zur TextFilterung
import java.rmi.*;
public interface RMITextFilter extends Remote
{
public String filterString(String str) throws RemoteException;
}
• Quelldatei mit Definition eines Interfaces für Text-Filter (TextFilter.java)
(gleiches Interfaces wie im Beispiel zur INET-Socket-Kommunikation)
// TextFilter.java
// Definition eines Interfaces fuer Klassen zur TextFilterung
public interface TextFilter
{
public String filterString(String str);
}
FACHHOCHSCHULE MUENCHEN
FACHBEREICH ELEKTROTECHNIK UND INFORMATIONSTECHNIK
FG TECHNISCHE INFORMATIK
V – JV – 825 – 02 – TH – 01
-----------------------------------------------------------------------------------
Einfaches Demonstrationsbeispiel zu RMI in Java (2)
• Quelldatei mit der Definition der RMI-Server-Klasse (RMIFilterServer.java)
//
//
//
//
RMIFilterServer.java
Start-Klasse eines Servers zum Filtern von Strings
Implementierung des Remote-Interfaces RMITextFilter
Einfaches Demo-Beispiel zu RMI
import java.rmi.*;
import java.rmi.server.*;
public class RMIFilterServer extends UnicastRemoteObject
implements RMITextFilter
{
TextFilter fil;
public RMIFilterServer(TextFilter tf) throws RemoteException
{ super();
fil = tf;
}
public String filterString(String str) throws RemoteException
{
try
{ System.out.println("Remote-Aufruf von : " + RemoteServer.getClientHost());
}
catch (ServerNotActiveException ex)
{ System.err.println("kein Remote-Aufruf");
}
return fil.filterString(str);
}
public static void main(String[] args)
{
if (System.getSecurityManager() == null)
System.setSecurityManager(new RMISecurityManager());
try
{ RMITextFilter fil = new RMIFilterServer(new UpcaseFilter());
Naming.rebind("TextFilter", fil);
System.out.println("TextFilter bound in Registry");
}
catch (Exception ex)
{ System.out.println("RMIFilterServer error : " + ex.getMessage());
ex.printStackTrace();
}
}
}
• Beispiel einer Text-Filter-Klasse : Quelldatei UpcaseFilter.java
(gleiche Klasse wie im Beispiel zur INET-Socket-Kommunikation)
// UpcaseFilter.java
// Klasse zur Filterung von Strings : Umwandlung aller Buchstaben in Gross-Buchstaben
// Implementierung des Interfaces TextFilter
public class UpcaseFilter implements TextFilter
{
public String filterString(String str)
{
return str.toUpperCase();
}
}
FACHHOCHSCHULE MUENCHEN
FAKULTÄT ELEKTROTECHNIK UND INFORMATIONSTECHNIK
FG TECHNISCHE INFORMATIK
V – JV – 825 – 03 – TH – 02
-----------------------------------------------------------------------------------
Einfaches Demonstrationsbeispiel zu RMI in Java (3)
• Quelldatei mit der Definition der RMI-Client-Klasse (RMIFilterClient.java)
// RMIFilterClient.java
// Filterung von Strings, die ueber die Standardeingabe eingegeben werden
// Einfaches Demo-Beispiel zu RMI
import java.rmi.*;
import java.io.*;
public class RMIFilterClient
{
static final String DEF_HOST = "localhost";
public static void main(String[] args)
{
String host = DEF_HOST;
if (args.length>0)
host = args[0];
String server = "//"+host+"/"+"TextFilter";
if (System.getSecurityManager() == null)
System.setSecurityManager(new RMISecurityManager());
try
{
RMITextFilter fil = (RMITextFilter) Naming.lookup(server);
PrintStream stdout = System.out;
BufferedReader stdin = new BufferedReader(new InputStreamReader(System.in));
String line;
stdout.print("Eingabe ? ");
while ((line = stdin.readLine()) != null)
{
line = fil.filterString(line);
stdout.println("Ausgabe : " + line);
stdout.print("Eingabe ? ");
}
// RMI-Aufruf !!!
}
catch(Exception ex)
{
System.err.println("RMIFilterClient Exception : " + ex.getMessage());
ex.printStackTrace();
}
}
Herunterladen