Projekt: RMI RPC und JNI Systemprogrammierung Wintersemester 2007/2008 Systemprogrammierung Wintersemester 2007/2008 Teilnehmer Abdelkarim Kodssi Schwerpunkt: RMI und RPC U-Yeol Suk Schwerpunkt: JNI Systemprogrammierung Wintersemester 2007/2008 • Kapitel 1 RMI und RPC • Kapitel 2 JNI Systemprogrammierung Wintersemester 2007/2008 Java RMI Kapitel 1.RMI -Was ist RMI? -Ziele von RMI -RPC -Unterschied zu RPC Kapitel 1.2 Funktionsweise von RMI -RMI Kommunikations-Architektur -RMI Elemente und Ablauf Kapitel 1.3 Code Beispiele -Remote Interface definieren -Remote-Object implementieren -Server implementieren -Client implementieren Systemprogrammierung Wintersemester 2007/2008 1.RMI ØWas ist RMI? ü RMI steht für Remote Method Invocation (entfernter Methodenaufruf) ü Realisiert Client-Server Modell ü RMI läuft nur auf Java rechner ü Basiert auf dem Prinzip von RPC ( remote procedur call ) Systemprogrammierung Wintersemester 2007/2008 1.RMI ØZiele von RMI ü Den Anwendungsprogrammierer hierbei zu unterstützen und ihm die aufwendige und fehleranfällige Implementierung eines solchen Protokolls abzunehmen. ü Zu den indirekten Zielen von RMI gehört es Lastausgleich von Programmen zu ermöglichen, sowie die Skalierbarkeit von Programmen zu erhöhen. Systemprogrammierung Wintersemester 2007/2008 1.RMI ØRPC Abb. 1 RPC Prinzip Systemprogrammierung Wintersemester 2007/2008 1.RMI ØRPC ü RPC steht für Remote Procedure Call und wurde 1983 vorgestellt ü Den Zugriff auf entfernte Serverfunktionen aussehen zu lassen und so die Komplexität der Netzwerkprogrammierung vor den Anwendungsprogrammierer zu verbergen ü Die eigentliche Verbindung zwischen Server und Client übernehmen sog. Stellvertreterobjekte (engl. proxies). Systemprogrammierung Wintersemester 2007/2008 1.RMI ØUnterschied zu RPC ü RPC und RMI scheinen identisch zu sein, beide arbeiten mit Sockets ü RPC ist nicht für objektorientiertes Arbeiten geeignet Systemprogrammierung Wintersemester 2007/2008 1.2 Funktionsweise von RMI ØRMI Kommunikations-Architektur Abb. 2 RMI Kommunikations-Architektur Systemprogrammierung Wintersemester 2007/2008 1.2 Funktionsweise von RMI ØRMI Kommunikations-Architektur üDie Transportschicht (Netzwerverbindung) umfasst hierbei das Host OS, den sog. Networklayer und das Netzwerkkabel. üDas Remote Reference Layer umfasst die Verbindungs-Semantik, d.h. es implementiert die Übertragungsprotokolle und die Verbindungsdetails. üStub/Skeleton Schicht verbirgt die komplizierten Details der Kommunikation. Systemprogrammierung Wintersemester 2007/2008 1.2 Funktionsweise von RMI ØRMI Elemente ü Das Remote-Interface definiert die Funktionen, die auf dem Server zur Verfügung stehen sollen und Beschreibt damit das Verhalten derentfernten Funktionen (ohne dieses Verhalten zu implementieren). ü Die Remote-Objekte implementieren das Remote-Interface und das Verhalten der entfernten Funktionen. Systemprogrammierung Wintersemester 2007/2008 1.2 Funktionsweise von RMI ØRMI Elemente ü Beim Namens-Dienst (RMI Registry) werden die Remote-Objekte vom Server registriert und die Referenzen auf diese RemoteObjekte können von den Clients abgefragt werden. ü Als Remote-Referenzen werden die Referenzen auf Remote- Objekte bezeichnet. Systemprogrammierung Wintersemester 2007/2008 1.2 Funktionsweise von RMI ØRMI Elemente und Ablauf Abb. 3 RMI: Elemente und Ablauf Systemprogrammierung Wintersemester 2007/2008 1.2 Funktionsweise von RMI Ø RMI Ablauf Der Ablauf lässt sich damit wie folgt beschreiben: ü Zuerst wird die RMI Registry mit dem Befehl $ start rmiregistry über die Befehlskonsole auf dem Server gestartet. ü Danach instanziiert der Server ein oder mehrere Remote-Objekte und meldet diese mit der Funktion Naming.bind(), die Bestandteil des RMI-Pakets ist, bei der RMI Registry an. Systemprogrammierung Wintersemester 2007/2008 1.2 Funktionsweise von RMI Ø RMI Ablauf ü Im dritten Schritt erfragt der Client mit der Funktion Naming.lookup() von der RMI Registry eine Referenz auf das entfernte Objekt und ist danach in der Lage auf dieses zuzugreifen. ü Jetzt kann der Client die entfernte Funktion aufrufen und erhält ü im fünften und letzten Schritt den Rückgabewert bzw. eine Exception zurück, wenn bei der Kommunikation ein Fehler aufgetreten ist. Systemprogrammierung Wintersemester 2007/2008 1.3 Code Beispiele Abb. 4 Implementierungsschritte Abbildung soll einen Überblick über die einzelnen Schritte bei der Implementierung geben und die relevanten Elemente hervorheben. Systemprogrammierung Wintersemester 2007/2008 1.3 Code Beispiele ØRemote Interface definieren Das Remote-Interface definiert die Funktionen, die auf dem Server zur Verfügung stehen sollen. import java.rmi.*; public interface Adder extends Remote { int add( int x, int y ) throws RemoteException; } Systemprogrammierung Wintersemester 2007/2008 1.3 Code Beispiele ØImplementierung des Remote-Interface Das Remote-Object implementiert das Verhalten der entfernten Funktionen public class AdderImpl extends UnicastRemoteObject implements Adder { public AdderImpl()throws RemoteException{} public int add( int x, int y ) throws RemoteException { return x + y; } } Systemprogrammierung Wintersemester 2007/2008 1.3 Code Beispiele ØServer Implementieren Der Server ist ein „normales“ Java-Programm public class Server { public static void main( String[] args ) { try { AdderImpl adder = new AdderImpl(); Naming.bind("Adder",adder ); } catch(Exception e) { // Registrieren des Remote-Objects fehlgeschlagen } } System.out.println("Adder angemeldet"); } Systemprogrammierung Wintersemester 2007/2008 1.3 Code Beispiele ØClient implementieren import java.rmi.*; public class Client { public static void main( String[] args ) { try{ Adder adder = (Adder) Naming.lookup( "Adder" ); System.out.println( adder.add( 49, 11 ) ); } catch(Exception e) { // Zugriff auf Remote-Object fehlgeschlagen } } } Systemprogrammierung Wintersemester 2007/2008 1.3 Code Beispiele ØRMI-Registry starten • Vor dem Start der Anwendung ist die rmiregistry zu starten mit Hilfe des rmiregistry-Kommandos. Rmiregistry ist eine einfacher Server-seitiger Namensdienst: ü Auf UNIX-basierten Systemen: rmiregistry & [PORT] ü Auf Windows-Systemen: start rmiregistry [PORT] Systemprogrammierung Wintersemester 2007/2008 Java Native Interface (JNI) • Kapitel 2.1 Was ist JNI? • Kapitel 2.2 − − − − Vorgehensweise beim Erstellen des JNI-Programms Erstellen der Java-Klassen Compilieren der Java-Klasse Erzeugen der Headerdateien aus den Java-Klassen − − − − − − Implementierung der Methode in C Kompilieren der C-Funktionen Parameter Übergabe in JNI JNI Sinaturen Strings C ruft Java-Methode auf Kapitel 2.3 • Fazit • Quelle für RMI ,RPC und JNI Systemprogrammierung Wintersemester 2007/2008 2.1 Was ist JNI? Bei JNI handelt es sich um eine Schnittstelle der JVM. Diese ermöglicht den wechselseitigen Zugriff zwischen Java-Anwendungen auf der einen und plattformspezifischen (nativen) Bibliotheken und Anwendungen auf der anderen Seite. Dies ist in folgenden Situationen sinnvoll: • Die Java Class Library unterstützt gewisse plattformabhängige Features nicht, die Ihre Applikation benötigt. • Es existiert bereits eine Library in einer anderen Programmiersprache und Sie wollen diese Funktionen beliebigen JavaApplikationen zugänglich machen. • Ihre Applikation enthält Teile, die zeitkritisch sind. Systemprogrammierung Wintersemester 2007/2008 2.2 Vorgehensweise beim Erstellen des JNI-Programms 1Erstellen der Java Klassen Prog.java 2. Compilieren 3. Header-File erzeugen prog.h 4. Schreiben des C Programmes Prog.class prog.C jni.h 5. Compilieren des C/C++ Programmes 6. Starten des Programmes prog.dll Systemprogrammierung Wintersemester 2007/2008 2.2 Erstellen der Java-Klassen • Deklarieren der nativen Methoden private static native double callnative( int input_i, String input_str, float input_f ); • Laden der c-Library in die Java-Klassen static { System.loadLibrary(„add); } Nach Aufruf der loadLibrary Funkt. kann die Methode private static native double callnative() aufgerufen werden. 2.2 Erstellen der Java-Klassen class Prog { static int i = 2; static float f = (float)3.50; static double d = 0.20; static String str = "Vorher"; //Deklarieren der native Methoden private static native double callnative(int input_i, String input_str, float input_f); public static void main(String[] args) { double erg = callnative(i, str, f); System.out.println(„Ergebnis =" + erg); } static { System.loadLibrary(„add"); } } 2.2 Erstellen der Java-Klassen • Eine Alternative zu loadLibrary(String) ist die Methode load(String). • Im Gegensatz zu loadLibrary() erwartet load() einen absoluten Pfad zur Bibliothek. Systemprogrammierung Wintersemester 2007/2008 2.2 Compilieren des Java-Programm Der Befehl javac Prog.java erzeugt das class-File Prog.class Systemprogrammierung Wintersemester 2007/2008 2.2 Header Files aus den Java-Klassen erzeugen Der Befehl javah -jni prog.h Prog erzeugt das Header-File prog.h Systemprogrammierung Wintersemester 2007/2008 2.2 Header Files aus den Java-Klassen erzeugen #include <jni.h> /* Header for Java_Prog_callnative */ #ifndef _Included_Prog_callnative #define _Included_Prog_callnative #ifdef __cplusplus extern "C" { #endif … /* Class: Prog * Method: callnative * Signature: (I, F, Ljava/lang/String;" )D */ … JNIEXPORT jdouble JNICALL Java__Prog_callnative (JNIEnv *env, jclass input_cls, jint input_int, jstring input_string, jfloat input_float); #ifdef __cplusplus } #endif #endif Systemprogrammierung Wintersemester 2007/2008 2.2 Header Files aus den Java-Klassen erzeugen Deklaration der Übergangsparameter der Funkt. Callnative in der Headerdatei prog.h JNIEXPORT jdouble JNICALL Java__Prog_callnative (JNIEnv *env, jclass input_cls, jint input_int, jstring input_string, jfloat input_float); Der Übergabeparameter JNIEnv *env ist als ein Zeiger auf das JNI-Environment-Interface zu verstehen. Durch diesen Pointer kann man von C aus auf die JNI Methoden zugreifen. Systemprogrammierung Wintersemester 2007/2008 2.3 Implementierung der Methode in C /*add.c*/ #include <stdio.h> #include <math.h> #include <jni.h> #include „prog.h" JNIEXPORT jdouble JNICALL Java_Prog_callnative(JNIEnv *env, jclass input_cls, jint input_int, jstring input_string, jfloat input_float) Systemprogrammierung Wintersemester 2007/2008 2.3 Implementierung der Methode in C { /* Java_String in C_String konvertieren und an C_Variable zuweisen */ const char *c_string = (*env)->GetStringUTFChars(env, input_string, 0); /* Adresse des Feldes „d" in der der aufrufenden Klasse lokalisieren: */ jfieldID jfid = (*env)->GetStaticFieldID(env, input_cls, „d", "D"); /* Wert des Feldes „d" aus der aufrufenden Klasse auslesen: */ double input_double = (*env)->GetStaticDoubleField(env, input_cls, jfid); printf("%s %lf + pow(%d,%f)\n", c_string, input_double, input_int, input_float); return (input_double + pow(input_int, input_float)); } 2.3 Kompilieren der C-Funktion • Testprogramm unter Linux aus der C-Quellcode Datei add.c die shared library add.so generiert: gcc -shared -l/usr/local/java/include l/usr/local/java/include/linux add.c -o libadd.so 2.3 Kompilieren der C-Funktion • Unter Windows wurde die Library add.dll mit folgendem Aufruf des Microsoft Visual C++ Compilers erstellt: cl -Ic:\java\include -Ic:\java\include\win32 MD -LD add.c -Feadd.dll Systemprogrammierung Wintersemester 2007/2008 2.3 Parameter Übergabe in JNI Folgende Tabelle gibt Aufschluss wie die Java-Datentypen in C gesehen werden: Java Typ • • • • • • • • • boolean byte char short int long float double void Native C-Typ jboolean jbyte jchar jshort jint jlong jfloat jdouble void unsigned, 8 bit signed, 8 bit unsigned, 16 bit signed, 16 bit signed, 32 bit signed, 64 bit 32 bit 64 bit Systemprogrammierung Wintersemester 2007/2008 2.3 Die JNI Signaturen Java Typ • boolean • byte • char • short • int • long • float • double • fully-qualified-class • type[] • method type • void Signatur • Z • B • C • S • I • J • F • D • L fully-qualified-class • [ type • (arg-types) reg-type • V Beispiel: (IJDF)Z ist die Signatur einer Methode, welche vier Argumente ( int, long, double, float) hat und einen boole‘schen Wert zurückgibt. Systemprogrammierung Wintersemester 2007/2008 2.3 Java Strings JNI benutzt eine UTF-Codierung um Strings plattformunäbhangig darzustellen. Für die Verarbeitung von UTF Strings stehen in der jni-Library die folgenden C Methoden zur Verfügung: · jstring NewStringUTF(const char* bytes) erzeugt ein neues java.lang.String Objekt. · const jbyte* GetStringUTFChars(jstring string, jboolean* isCopy) gibt einen Pointer auf einen Array von UTF-Characters zurück. · void ReleaseStringUTFChars(jstring string, const char* str) gibt den (neu alloziierten) Speicherplatz für str frei. Systemprogrammierung Wintersemester 2007/2008 2.3 Aufruf von Java Methoden aus C • GetObjectClass(jobject obj) gibt die Klasse des Objektes obj zurück. • jmethodID GetMethodID( jclass class, const char* name, const char* sig) gibt die Methoden-Nummer der Methodenname der Klasse mit Signatur sig zurück. Call<Type>Method( jobject obj, jmethodID methodID, para1 usw... ) Systemprogrammierung Wintersemester 2007/2008 2.3 Aufruf von Java Methoden aus C Beispiel Code: JNIEXPORT void JNICALL Java_MyFrame_process(JNIEnv *env,jobject obj, jstring string) { const char *str = env->GetStringUTFChars(string, 0); len = strlen(str); jclass jmf = env->GetObjectClass( obj ); jmethodID mid = env->GetMethodID( jmf, "setLength", "(I)V" ); env->CallVoidMethod( obj, mid, (jint)len ); } Systemprogrammierung Wintersemester 2007/2008 Fazit Die Beispiele haben gezeigt, wie mit JNI Zugriffe zwischen na-tiver Welt und Java-Welt bewerkstelligt werden können und wie daraus resultierenden typischen Implementierungsproblemen begegnet werden kann. Das JNI kann insbesondere bei der Entwicklung von Systemsoftware große Dienste leisten, es bietet der nativen Seite vielfältige Möglichkeiten, die Java-Plattform zu nutzen. Doch neben den Vorteilen sind auch Risiken zu nennen. Da sowohl native Anwendungsteile als auch die JVM im gleichen Adressraum laufen, führt z. B. eine Zugriffsverletzung auf na-tiver Seite auch zum Absturz der JVM. Die Verwendung des JNI setzt also sowohl eine tiefere Kenntnis der JVM als auch der Zielplattform voraus. Quelle für JNI • • • • • • http://java.sun.com/products/jdk/1.2/docs/guide/jni/index.html http://java.sun.com/docs/books/tutorial/native1.1/index.html http://ringlord.com/platform/java/jni-howto.html http://www.javaworld.com/javaworld/jw-10-1999/jw-10-jni.html http://codeguru.developer.com/java/JNI/index.shtml http://mindprod.com/jni.html Quelle für RMI RPC • Internet http://java.sun.com/javase/technologies/core/basic/rmi/index.jsp http://java.sun.com/j2se/1.4.2/docs/guide/rmi/getstart.doc.html http://www.lrzmuenchen.de/services/compute/linuxcluster/cpjava/rmi.html http://www.mm.informatik.tu-darmstadt.de/courses/helpdesk/rmi_tutorial.html http://www.bs.informatik.uni-siegen.de/www/lehre/ws0506/csp/index_html http://www.commentcamarche.net/rmi/rmiintro.php3 • Literatur • Java Enterprise In A Nutshell (ISBN 3-89721-334-6) • J2EE und Jboss Verteilte Enterprise Applikation auf der Basis von J2EE,JBoss & Eclipse (ISBN 3-446-40508-9)