RMI - Client von Server komplett trennen?

Hello Guys

Ich versuche mich weiterhin im Bereich Server/Client fortzubilden. Nun bin ich beim Thema RMI.

Ich habe mir ein Projekt erstellt und eine Server, Client, Controller, Klasse erstellt sowie einen ControllerInterface.

Die Controller Klasse hat nur eine Methode sayHello und gibt Hello World auf der Konsole aus. Beim Aufbau habe ich mich an die RMI Kapitel von Java ist auch eine Insel von Christian Ullenboom gehalten.

Es funktioniert wunderbar, ich starte die Server Klasse dann die Client Klasse im Log des Servers sehe ich dann Hello World was richtig richtig cool ist.

Aber moment mal? Ich dachte bis jetzt RMI ist dafür da um Entfernte Objekte zu benutzen. Das heisst ich habe mir vorgestellt mit einem CLient einen Server über Netzwerk zu steuern. Wenn die Client Klasse aber im selben Projekt Ordner ist wie der Server dann habe ich in meinen Augen nichts erreicht im vergleich zu normalen Sockets so entfernt ist die Client Klasse dann doch nicht vom Server.

Also habe ich zwei verschiedene Projekte angelegt. Einen nur für den Server und einen nur für den Client. Jetzt habe ich es nochmal gestartet und das gleiche Ergebnis erwartet “Hello World”.

Stattdessen kam aber


Exception in thread "main" java.rmi.UnmarshalException: error unmarshalling return; nested exception is: 
	java.lang.ClassNotFoundException: rmiVersuch.ControllerInterface(no security manager: RMI class loader disabled)
	at sun.rmi.registry.RegistryImpl_Stub.lookup(Unknown Source)



Die beste Antwort bei StackOverflow war “Pack den Client in das selbe Projekt wie Server” :suspect:

Was ist da los?

*** Edit ***

Ich habe noch vergessen zu schreiben ich nutze auf der Server Seite mit

  System.setProperty("java.security.policy", "C:\\....policy.policy");
         System.setSecurityManager(new SecurityManager());

Diese Datei

grant {

    permission java.security.AllPermission;
};

*** Edit ***

Sry für das spammen aber ich habe den Fehler gefunden. Auf der Client seite muss das Interface im exakt dem selben Packetnamen liegen. Ich finde das merkwürdig muss das wirklich so sein?

Im Server liegt ControllerInterface im package serverRMI
Im CLient liegt ControllerInterface im package clientRMI

Das resultiert in einer Exception ändere ich den Namen des packages im client zu serverRMI funktioniert das.

Öhm ja das muss so sein,
vergiss nicht das packages nicht einfach nur kunterbunte lustige Codeverschönerungen sind sondern fester Teil der Java Sprache.

Viele gewöhnen sich an packages zu verwenden weil die IDE immer anmeckert nicht das default package zu verwenden, führt dann aber dazu das Packagenamen nach gut dünken vergeben werden und was sich halt gerade “cool” und “seriös” anhört und nicht nach dem eigentlichen Nutzen.

@TO
Darum baut man RMI auch mit drei Packages : client, server und common.
Klassen die beide Seiten kennen und die auch auf beiden Seiten verfügbar sein müssen kommen in das common-Package.
Wenn man mit einer IDE arbeitet baut man erst das common-Package und bindet dies jeweils beim Client und Server als Abhängkeit mit ein.

ABER :

Vor nicht all zu langer Zeit war schon mal das Thema RMI, und ich kann dir sagen : LASS ES ! Nutz es nur wenn es wirklich nicht anders geht (was ich mir erlich gesagt nicht vorstellen kann das es auch nur einen sinnvollen use-case dafür geben sollte) !

Grund : Es muss auf dem Server nicht nur ständig die RMI-Registry laufen und erreichbar sein, sondern für jede neue Instanz des Server-Codes vergibt die RMI-Registry einen random-Port, so dass sinnvolle Firewall-Regeln ausgehebelt werden.
(Anmerkung : Möglich das es machbar ist da irgendwelche Vorgaben zu machen, aber soweit habe ich mich dann nicht mehr mit befasst.)
Hast du also erstmal die Server-Instanz laufen, musst diese aber auf Grund eines Fixes neu starten so hat die Instanz plötzlich einen anderen Server-Port (spielt bei RMI weniger die Rolle da dieser von der Registry an den Client übergeben wird). Und jedes Mal die Firewall neu konfigurieren nur weil man die Server-Instanz neu starten muss … naja, wie gesagt : an dem Punkt war für mich Schluss mit RMI. Ich will mich auch gar nicht weiter mit befassen. Wozu auch ? Einfach ein ServerSocket (der immer am gleichen Port hängt) und ein paar String-Kommandos … und gut ist. Einfacher, schneller zusammengeklebt und deutlich einfacher zu debuggen.

Klar, so als Übungsaufgabe mal ganz lustig, aber im Produktiven sehe ich nur innerhalb eines LANs wirklich Sinn drin, ansonsten ist der Aufwand den man hat bezüglich Sicherheit schlicht zu groß.

Hahaha nein RMI ist ganz sicher nicht nutzlos, dafür bauen zuviele Folgetechnologien darauf auf.
Durch das alter von RMI (noch unter Sun entwickelt) kann man schnell fehlschließen es wäre überholte Technologie.
Wenn dann wird es eher oft fehlgenutzt, häufig als die heutig klassischen ServerClient Verbindungen bei dem Beide unabhängig arbeiten und nicht als ein zusammengeschlossenes Programmnetzwerk unabhängig dem Aufenthaltsort.

Warum bei dir jetzt aber die Ports durchwechseln ist mir aber nicht klar?
Habe RMI seit über einem Jahr nicht mehr benutzt kann mich aber nicht an solch derartigen Portprobleme erinnern.
Fakt ist nur: Es gibt kein Server oder Client, ein Programm verbindet sich nur zuerst und sowohl “Client” als “Server” müssen entsprechend ihre Ports geöffnet haben.
Server und Client würde bedeuten es gibt einen zentralen Rechner der die Kommunikation übernimmt, das stimmt aber nicht sondern die Programme verbinden sich untereinander wie Abhängikeiten über ein beliebiges Medium (ob im selben Ordner oder auf der anderen Seite der Welt) kreuz und quer zu einem einzigen Program zusammen.

Nur kommt bei bei den Meisten dann irgendwelche Chatprogramme oder andere Server/Client verbindungen bei raus.
Dann auf jedenfall, go for plain TCP oder UDP.

Server == ~ übernimmt zentrale Berechnung,- beide kommunizieren aber.

Interfaces trennt diese und diese Implementierung (sollte es eigentlich).

Was mich stört daran, gegenseitige Methodenaufrufe,- wie? “Server” sendet nur eine Kopie seiner Rückgabe eines Methodenaufrufs,- keine Referenz, auf der dann auch wieder etwas aufgerufen werden könnte. -, distributed GC.

Ach Quatsch, es geht um die Parameter aber die werden auch volls kopiert.

Mag ja sein das es irgendwelche Szenarien gibt bei denen RPC (im allgemeinen) sinnvoller ist als ein eigenes Protokoll (bzw re-use eines vorhandenen), aber ich kenne leider keines, oder zumindest soweit : keines das sich nicht auch mit einfachen String-Commands und ggf Base64-Daten umsetzen lässt. Und davon abgesehen : wie gesagt, ich hatte einige Probleme auch nur das Beispiel aus dem Sun-Tut überhaupt ans laufen zu bekommen, und war am Ende trotzdem ziemlich verwirrt und weis bis heute nicht wo wann was wie ausgeführt wurde.

Das es bei RMI in dem Sinne keine klare Rollentrennung Client-Server gibt haut soweit nur halb hin. Die einzelnen “Pakete” an sich sind wie normale Parts eines Programms, stimmt schon soweit. Der “Server” in dem Sinne ist die RMI-Registry bei der sich alle melden um überhaupt miteinander arbeiten zu können. Jedoch verwaltet die Registry nur die Instanzen und bringt halt die beteiligten Seiten zu einem Punkt zusammen. Das dann mindestens von einem Part ein entsprechner “Zugriffspunkt” in Form eines Sockets bereitsgestellt werden muss lässt sich (zumindest bei Netzwerk-Traffic) nicht vermeiden. Das es dabei aber zu Problemen wie Random-Ports, Firewall-Restrictions oder NAT kommen kann wird gerne mal verschwiegen.

Wer mir für RMI ein Beispiel liefern kann bei dem es eben Vorteile bringt direkt RPC zu nutzen mag mir dieses bitte erklären, ich werde auch nicht widersprechen.
Aber von dem was ich bisher so mit gemacht habe wäre es mir persönlich schlicht zu stressig, auch wenn ich selbst über das Level des Anfängers hinaus bin, und denke das es für jemand der noch nicht viel mit Netzwerkkommunikation zu tun gehabt hat zu umständlich ist. Fast so als würde man alle direkt zwingen NIO-channels zu nutzen ohne vorher die Grundlage der Streams zu erklären.

So weit ich weiß bzw. auch selbst probiert habe, scheint es nicht möglich sich vom RMI-Server zu trennen. Der Client wird bei einem “unbind” eines vorher in die RMI-Registry exportierten Remote-Objektes das Objekt zwar wieder aus seiner RMI-Registry entfernen, jedoch wird die Verbindung zum Server dadurch nicht unterbrochen.
So lange der RMI-Client läuft, hält er offenbar auch die Verbindung zum RMI-Server.
Auch wenn man den Server beauftragt, das Remote-Objekt aus seiner Registry zu entfernen, wird dadurch die Verbindung des Clients zum Server nicht unterbrochen.