RMI Callback - Blocking?

Hey Leute

Bin seit heute im Forum, da ich den glauben an java-forum.org verloren hab.
Programmiere gerade ein Client-Server-Spiel auf RMI basis
Login und so funktioniert. Nur die Callbacks bringen Fragen über Fragen.
Meine Problem ist das unterbrechen von Callbacks und der asynchrone aufruf von methoden
Also:
Wenn ich auf dem Server die Methode XY aufrufe dann übergebe ich ein Object für den Callback.
Wenn ich nun einen aufruf auf diesem Object mache dann wird die methode beim client aufgerufen.
In der methode beim client kann aber allesd mögliche passieren.
Was wenn dort der Client einfach einen endlos schleife einbaut - dann wartet der server ewig auf ein ende der methode.

Irgentwo habe ich gelesen das es auch mit Polling gehen soll.
aber das würde mir eigentlich nicht gefallen.
Gibt es in RMI eine möglichkeit denaufruf der methode nach 3 sec abzubrechen.
oder gibt es die möglichkeit garnicht auf das ergebnis der methode zu warten?
-> quasi einfach clientMethods.methode();
und auf das ergebnis wird nicht gewartet

mfg

‘timeout’ ist der Fachbegriff, falls unbekannt, kannst danach (und natürlich noch RMI + evtl. CallBack) suchen,
ich habe aber leider auf die Schnelle nichts gutes gesehen

ansonsten selber agieren…, jetzt wird es aber unsauber:
Callback-Vorgang kenne ich selber noch nicht, vielleicht beim Callback-Start einen zweiten Thread starten,
der wartet und den ersten gegebenenfalls nach paar sec mit dem höchsten Mittel, Thread.stop(),
aus der Ruhe bringt,

auf den Client muss das nicht unbedingt Auswirkung haben, auf allen Seiten vielleicht generell ein Thread,
der alle anderen Threads kontrolliert, erkennt welche System-Threads sind, und welche eigene/ RMI,
alle diese sollten sich an ihrem Anfang besser allgemein angemeldet haben, von Zeit zu Zeit zurückmelden,
sonst nach einer gewissen Gnadenfrist gnadenlos beendet (Thread.stop() ),

Du musst den Client-Callback asychronisieren. D.h. der Callbackaufrug, getriggert vom Server, muss beim CLient in einem anderen Thread behandelt werden, so dass der Callback sofort zurück kommen kann, die ausführung beim Client aber ggf. noch weiter läuft.

Der Server kann sich ja “merken” dass er den Callback gestartet hat. Und wenn der Client dann nach “drölf” Tagen entscheidet die durch den Callback hervorgerufene Dialogbox zu schließen und dann erst dem Server antwortet, dann kann der Server ja die Antwort verwerfen, weil es länger als die geplanten 3 sekunden gedauert hat.

Alles in allem: RMI hilft dir dabei nicht. Das musst du selbst machen.

SIMON hingegen hat ein Feature, mit dem du für bestimmte Methoden ein “Invocation Timeout” definieren kannst. Allerdings sollte man damit sparsam umgehen und lieber die Implementierung sauber halten (siehe oben).

Gruß
Alex

Hey danke für die Antworten

Ich hab die ganze zeit das Problem im Kopf:
wenn jemand den Java code verändert - also beim client
und der server eine methode beim client aufruft dann kann alles mögliche passieren
also könnte er auch ein Thread.sleep(10000000000…) ein bauen
und der Server würde dann auch ewig warten.
Das starten in einem extra Thread finde ich auch unsauber da ich den Thread ja auch irgentwie beenden will.
Un RMICalls sind auch schwer abzubrechen

Den Callback brauche ich um dem Client mitzuteilen das isch etwas verändert hat.
z.B: JETZT IST EINE NEUE NACHRICHT DA, JETZT STARTET DAS GAME, JETZT BRAUCHE ICH EINEN ZUG VON DIR

Das mit den Nachrichten kann ich durch polling lösen. Habe mir das so vorgestellt.
Der Client ruft getNachrichten auf und diese Methode liefert die aktuelle Nachrichten zurück
wenn keine Nachrichten vorhanden sind wird ein wait() auf gerufen und solange gewartet bis wieder eine nachricht da ist
Die Methode wird in einem Thread Beim client in einer endlos schleife aufgerufen
Mit den anderen Sachen hab ich mir des auch so vorgestellt.
Somit brauche ich garkeine callbacks mehr(hoffentlich) und somit werde ich auch keine probleme mit der FIREWALL bekommen.

Das einzigste Problem: wenn ich den server beenden will muss ich die ganzen poll mehtoden sauber beenden. Da ich das LockObject mit notifyall() aufwecken muss und danach die methode stoppen.

EINE FRAGE BLEIBT. Wenn der Client eine poll methode aufruft hängt er ja auch fest bis er eine antwort bekommt.
Wenn der client aber beenden will muss ich den thread irgentwie stoppen. Da dieser Thread aber einen RMI Call ausführt kann ich ihn nicht einfach interrupten oder?

mfg

Pollen habe ich bei mir auch eingebaut, sicher nicht ideal,
(edit: also ich habe Client-Anfragen, die im Server warten bis Ereignis, das ist ja gar nicht direkt ‚Pollen‘)

an Ende des Clients habe ich noch gar nicht gedacht, der ist bei mir mit System.exit(0) aus
und 20 sec später erst ein Server-Request fertig, scheint ohne weitere Fehlermeldung im Server zu gehen…

zu langes Warten im Server fand ich so oder so unschön,
halb wegen offener Netzwerk-Verbindungen,
halb durchaus wegen Fehler im Client oder gar Server für diesen Client,
und habe das von vornherein auf bis zu einer Minute begrenzt,
dabei wird nebenbei die Server-Uhrzeit übertragen :wink:

wenn es eine Nachricht gibt, dann sofort Update, ansonsten 0-60 sec warten genau bis zur nächsten vollen Minute

Nachteil dann evtl. noch mehr Netzwerkbelastungen durch neue Verbindungen oder zumindest noch mehr Nachrichten,
aber ich kenne die Details wenig genug um mir dazu keine größeren Sorgen zu machen, solange es läuft


edit:
ach ja, und halbwegs elegant im normalen Rahmen (ohne Fehler zu bedenken) wäre,
den Server zu diesem Zeitpunkt so zu informieren, dass das Pollen beendet wird,

der Client weiß selber natürlich schon Beschreid und pollt nicht noch mal,
ähnlich dem Ende einer Lese-Schleife auf Sockets,
selber kaum abbrechbar, aber etwas an Server schicken, der Antwort zurück, Lese-Schleife hört auf

[QUOTE=Unregistriert]Hey danke für die Antworten

Ich hab die ganze zeit das Problem im Kopf:
wenn jemand den Java code verändert - also beim client
und der server eine methode beim client aufruft dann kann alles mögliche passieren
also könnte er auch ein Thread.sleep(10000000000…) ein bauen
und der Server würde dann auch ewig warten.
[/quote]

Bei RMI wartet der wohl ewig. Ja. Das passiert bei SIMON nicht. Denn hier ist ein fest eingestellter Timeout vorhanden, so dass Methodenaufrufe zwar verdammt lange, aber nicht ewig dauern können (aktuell 1h). Und wenn dir eine Stunde zu viel ist, kannst du das noch selbst einstellen.

Das starten in einem extra Thread finde ich auch unsauber da ich den Thread ja auch irgentwie beenden will.

Threads lassen sich prima beenden. Du musst nur eine Abbruchbedingung einbauen. die Sache mit stop() ist bei einem Thread aber mit Vorsicht zu genießen.

Un RMICalls sind auch schwer abzubrechen

Afaik lassen die sich gar nicht abbrechen. Ebensowenig wie sich ein Methodenaufruf abbrechen lässt. Mir RMI hat das erstmal nix zu tun. Du musst nur schauen dass du sauber entwickelst und hier und da abbruchbedingungen einbaust.

Den Callback brauche ich um dem Client mitzuteilen das isch etwas verändert hat.
z.B: JETZT IST EINE NEUE NACHRICHT DA, JETZT STARTET DAS GAME, JETZT BRAUCHE ICH EINEN ZUG VON DIR

Eben wofür man Callbacks so einsetzt.

Das mit den Nachrichten kann ich durch polling lösen. Habe mir das so vorgestellt.
Der Client ruft getNachrichten auf und diese Methode liefert die aktuelle Nachrichten zurück
wenn keine Nachrichten vorhanden sind wird ein wait() auf gerufen und solange gewartet bis wieder eine nachricht da ist
Die Methode wird in einem Thread Beim client in einer endlos schleife aufgerufen
Mit den anderen Sachen hab ich mir des auch so vorgestellt.
Somit brauche ich garkeine callbacks mehr(hoffentlich) und somit werde ich auch keine probleme mit der FIREWALL bekommen.

Wozu der Stress? Dir geht’s doch hauptsächlich um die Sache mit dem durch den CLient blockierenden Thread am Server, oder?
In diesem Fall kann der Server über einen Callback eine Nachricht dem Client schicken. Die Nachricht wird aber mit dem Mehtodenaufruf nicht verarbeitet, sondern zur Verarbeitung in eine Liste/Queue gesteckt. Ein Thread im Client bearbeitet dann zyklisch/der Reihe nach alle Nachrichten die er in der Queue findet. Gibts gerade keine Nachrichten schläft der Thread. Gibt’s wieder neue Nachrichten, wird beim einfügen der Nachricht in die Queue der Thread wieder aufgeweckt.

Damit hast du kein lästiges Polling, der Client zwing den Server nicht zum schlafen weil er für die Verarbeitung lange bracht, und die hast nahezu 0 Zeitversatz (den du mit Polling hättest).

Okay, dann könnte man auf Clientseite immer noch den Code verändern und mutwillig ein Sleep von drölf trillionen Jahren einbauen. Aber da ist es wohl einfacher den Server anders in die Knie zu zwingen als da am Code rum zu fummeln.

Das einzigste Problem: wenn ich den server beenden will muss ich die ganzen poll mehtoden sauber beenden. Da ich das LockObject mit notifyall() aufwecken muss und danach die methode stoppen.

Was ist daran jetzt genau das Problem?

EINE FRAGE BLEIBT. Wenn der Client eine poll methode aufruft hängt er ja auch fest bis er eine antwort bekommt.
Wenn der client aber beenden will muss ich den thread irgentwie stoppen. Da dieser Thread aber einen RMI Call ausführt kann ich ihn nicht einfach interrupten oder?

Du verstrickst dich in was. Siehe meine letzter Lösungvorschlag.

Gruß
Alex

P.S. Oder nimm SIMON. Da hast du dein Timeout drin …

nebenher:

es geht ja immer um Threads, die nur an einem Aufruf ewig warten, die blockiert sind,
wenn man eine Schleife laufen hat, dann kann man reagieren, dann gibt es nie Probleme

Afaik lassen die sich gar nicht abbrechen. Ebensowenig wie sich ein Methodenaufruf abbrechen lässt. Mir RMI hat das erstmal nix zu tun.

Thread.stop() ist an und für sich schon mächtig, die einzige Möglichkeit

Okay, dann könnte man auf Clientseite immer noch den Code verändern und mutwillig ein Sleep von drölf trillionen Jahren einbauen. Aber da ist es wohl einfacher den Server anders in die Knie zu zwingen als da am Code rum zu fummeln.

die Fragezeichen stehen sicher eher bei Fehlern als Angriffen, synchronized-Deadlock, blockierte GUI durch Dialog oder wer weiß was alles

Wozu der Stress? Dir geht’s doch hauptsächlich um die Sache mit dem durch den CLient blockierenden Thread am Server, oder?
In diesem Fall kann der Server über einen Callback eine Nachricht dem Client schicken. Die Nachricht wird aber mit dem Mehtodenaufruf nicht verarbeitet, sondern zur Verarbeitung in eine Liste/Queue gesteckt. Ein Thread im Client bearbeitet dann zyklisch/der Reihe nach alle Nachrichten die er in der Queue findet. Gibts gerade keine Nachrichten schläft der Thread. Gibt’s wieder neue Nachrichten, wird beim einfügen der Nachricht in die Queue der Thread wieder aufgeweckt.

Damit hast du kein lästiges Polling und der Client zwing den Server nicht zum schlafen.

Okay, dann könnte man auf Clientseite immer noch den Code verändern und mutwillig ein Sleep von drölf trillionen Jahren einbauen. Aber da ist es wohl einfacher den Server anders in die Knie zu zwingen als da am Code rum zu fummeln.

naja der server sollte eigentlich absturz sicher sein :frowning:
Ich denke ich werde mich mal mit SIMON beschäftigen
Diese Timeouts hören isch echt gut an.

Hätte noch ne frage.
Wenn ich in RMI eine methode starte benutzt RMI doch ein wait() um auf die antwort zu warten
wenn ich dieses wait einfach unterbreche mit einem notify dann müsste der Thread auf keine antwort vom client warten und kann einfach weiter machen oder?
so kann der server in keinem callback „festhängen“

meine erster wille ist eigentlich das beim server NIE etwas blockiert, und er zu jeder zeit beendet werden kann

mfg

du meinst was der eine Rechner im RMI macht solange der andere Rechner arbeitet?
wird tuxedo bestimmt besser sagen können, aber um selber auch munter zu raten:
wenn die Kontrolle nicht eh an native Methoden übergeht, dann wird sicherlich gewartet, ja,

aber du kannst nicht notify() auf den Thread aufrufen oder so,
du kennst das interne Monitor-Objekt nicht, an welchem gewartet wird,

und selbst wenn das notify() klappte, wird danach sicher nicht blind beendet, wie auch immer das aussähe (welches Rückergebnis?),
sondern alle Bedingungen geprüft,
wahrscheinlich wird dann schlicht nochmal wait() aufgerufen…

naja der server sollte eigentlich absturz sicher sein
Ich denke ich werde mich mal mit SIMON beschäftigen
Diese Timeouts hören isch echt gut an.

Wie gesagt: Ich würde dennoch versuchen das auf Applikationsebene zu lösen. Der Timeout sollte nur der Sicherheit dienen.
Wenn du nicht weißt wielange ein Callback für gewöhnlich dauert (z.B. wenn er eine Dialogbox beim Client öffnet), dann schlage ich vor du baust dir einen weg drum herum. Im Fall der Dialogbox z.B. eine eigene Dialogbox die sich nach XX Sekunden mit einem Default-Rückgabewert schließt.
Wenn allerdings eine längerlaufende Implementierung dahinter hängt würde ich das in einen Thread auslagern.

Für die Sache mit „Pöser Pube verändert Code“: Da greift dann der Timeout.

Wenn ich in RMI eine methode starte benutzt RMI doch ein wait() um auf die antwort zu warten
wenn ich dieses wait einfach unterbreche mit einem notify dann müsste der Thread auf keine antwort vom client warten und kann einfach weiter machen oder?
so kann der server in keinem callback „festhängen“

Würde ich mich nicht drauf verlassen. SIMON würdest du mit dieser Weise nicht entblocken können, da wait() mit einem Timeout in einer schleife läuft. SIMON bricht die Schleife nach X durchläufen ab. RMI könnte aufgrund der fehlenden Timeout-IMplementierung dennoch weiter laufen.
Infinite-Wait ist an und für sich auch keine so tolle Idee in der Implementierung.

meine erster wille ist eigentlich das beim server NIE etwas blockiert, und er zu jeder zeit beendet werden kann

Bin mir nicht sicher. Aber wenn du mit RMI die Registry beendest, dann wird der zugehörige Socketserver auch beendet, was wiederum noch offenen Verbindungen kappt. Demnach kannst du so oder so jederzeit den Server runterfahren. Wäre ja noch schöner wenn ein Client einen regulären Shutdown verhindern könnte. Bei SIMON verhält es sich hier eigentlich genau so.

Gruß
Alex

Ja wahrscheinlich.

Naja ich meine von der Server seite aus wenn ich vom Client eine methode aufrufe
zb

public interface ClientMethodes extends Remote(){

public void methode1();    // diese methode wird vom server aufgerufen und der server soll nicht warten bis diese fertig ist

}


wie gesagt wenn ich es in einem extra thread aufrufen würde dann hätte ich das problem den thread zu beenden da er in einem RMI Call festhängt

Also werde jetzt mal mit SIMON anfangen. dann kann ich auch nach 3 Sekunden einfach abbrechen oder könnte ich sogar nach 0 sekunden einfach abbrechen?

Zu deinem Beispiel:

Wenn du nicht einigermaßen abschätzen kannst wie lange das dauert (im original zustand, also ohne Pseudo-Hacker-Eingriff), dann eindeutig: Ab damit in einem Thread. Evtl. so:

public ClientMethodsImpl implements ClientMethods {

public void methode1(){

new Method1Thread().start();

}

}

Also nur beispielhaft. Je nachdem was es da tatsächlich zu tun gibt kannst du “die Arbeit” auch erst in eine Liste/Queue stecken und einen WorkerThread aufrufen/wecken.

Ich betone nochmal:

Der InvokeTimeout von 1h dient nur der Sicherheit. Wenn 1h zu lang sind, kann man bei SIMON ein “CustomInvokeTimeout” definieren. Das jetzt aber dazu zu benutzen um Dinge frühzeitig abzubrechen ist keine gute Idee. In diesem Fall wird ein Fehler ausgelöst der wieder extra behandelt werden muss.

Also unbedingt zwischen folgendem entscheiden:

  1. Ich weiß wie lange etwas für gewöhnlich dauert. Darauf darf der Server ruhig mal 5sek warten. Oder auch mal 30sek.
  2. Ich nicht wie lange etwas dauert (Callback öffnet beim CLient eine Dialogbox und kehrt erst zurück wenn Dialogbox geschlossen ist, oder irgend eine größere Datenbearbeitung …)
  3. Ich möchte nicht dass ein Hacker meinen Server mit verändertem Code zum dauernden Warten verdonnert

Lösung für Fall 1:

Nix tun. Das läuft schon so. Und wenn’s doch mal 5min dauert: Who cares?!

Lösung für Fall 2:

Auslagern in einen Thread. Callback kehrt direkt zurück und das Ergebnis des lange dauernden Aufrufs später separat dem Server mitteilen

Lösung für Fall 3:

Entweder nix tun, dann liegt der Timeout für einen Methodenaufruf mit SIMON bei 1h. Oder eben das Timeout runterdrehen, z.B. auf eine Minute.

In keinemn Fall würde ich in 1 üder 2 auf ein CustomInvokeTimeout setzen. Das ist wie wenn der programmfluss von Exceptions abhängt. Das macht man nicht, das ist kein guter Code und das ist ein Feature-Missbrauch der mit späteren Versionen gern mal in die Hose gehen kann. Außerdem bindet man sich damit hart an die Bibliothek…

  • Alex

naja ich glaub so langsam muss ich mich wirklich darauf einlassen auch wenns mir nicht so gefällt :smiley:

bei SIMON werde ich keine probleme mit der FIREWALL ahben oder? (also bei den CALLBACKS)
von dem polling würdest du auch abraten oder?

achja danke für die tolle antwort :wink:

SIMON hat prinzipiell keine Firewall-Probleme. Du musst nur schauen dass der Server im Netz erreichbar ist. Entweder du hast einen (v)Root-Server. Dann musst du nur ggf. dessen Firewall so einstellen dass man von außen auf den Port von SIMON drauf kommt.
Oder der Server hängt an einem DSL-Anschluss hinter einem Router. Dann musst du nur dem DSL-Router Port-Forwarding für den von SIMON genutzten Port beibringen.

Beim Client muss nix konfiguriert werden. Solange der ungehindert ins Internet kommt, gibts da auch mit Callbacks keine Probleme. Wieso und warum das mit SIMON besser ist steht ja im SIMON Wiki beschrieben. Bei spezifischeren SIMON Fragen: Bitte das Support-Forum benutzen. Dann haben andere Hilfesuchenden auch was davon.

Zum Thema Polling:

Geht auch. Aber du musst dir im klaren sein dass das mehr Ressourcen fressen kann und eine Zeitverzögerung mit sich bringt.
Jeder Poll-Call lässt einen Thread warten. Und je mehr Clients du hast, desto mehr gleichzeitige Threads hast du. Hinzu kommt der Zeitversatz: Gepollt wird in der Regel mit einem bestimmten Zeitabstand. Und im Worst-Case musst du die komplette Zeit X warten bis du an das schon vorhandene Info-Paket ran kommst. Hängt aber von deiner Implemetierung ab.
Wenn es geht: Vermeide Polling.

Gruß
Alex

sry wenn sich das thema jetzt in richtung “Prozesse” entwickelt.
Ich plane auch eine art Lobby-Chat in dem alle Clients sind.
wenn Ich nun “X” Sessions also “X” User sind angemeldet
wenn nun User Nr5 eine nachricht schreibt dann muss ich allen anderen User mitteilen das eine neue Nachricht vorhanden ist. Also insgesamt brauche ich (x-1) threads die dann vom client die update methode aufrufen.
beim polling hätte ich auch X-1 threads aber da sie ja durch wait() im “halbschlaf” liegen ist der arbeitsaufwand doch nicht so groß oder?

also nochmal danke
werde mich jetzt erstmal in SIMON einarbeiten
wenn noch probleme zu SIMON auftreten schreib ich sie ins PROJECT_FORUM

mfg Stefan

wenn man bei einem Callback auf unmittelbare Verarbeitung vertraut, dann gibt es sicherlich nur einen Thread, der alle benachrichtigt,
wäre zu testen wie lange das dauert, bei hochskaliert hunderten User natürlich irgendwann interessant, allein von Übertragungszeiten her,
auch bei 10ms erfährt der hunderste erst nach 1 sec davon

wenig zu tun haben die Threads in allen Varianten, ob blockiert oder nicht, ob in Pausen da und nichts tuend,
alles sollte sich korrekt gebaut auf wait-Niveau befinden und dann nur wenig stören

Man kann hier zwei Strategien verfolgen:

  1. Entweder auf Callback-Sender-Seite (hier: Server) einen kleinen Thread-Pool mit dem verschicken der Callback beauftragen (Stichwort ExecutorService). Dann geht wenigstens nicht alle sequentiell raus. Würde bei einem großen Chat hier irgendwie bei 5 Threads anfangen.

  2. Oder auf Callback-Empfänger-Seite (hier: Client) die aufgerufene Methode kleinstmöglich halten und die eingehende Nachricht in eine Queue/Liste stecken und von einem oder mehreren Threads die Liste abarbeiten lassen.

Bei einem Chat würde ich auf Variante 1 setzen. Damit hast du dann noch den Vorteil dass lange Netzwerklaufzeiten gleich mitentkoppelt werden. Evtl. Variante 2 noch zusätzlich dazu. Kommt drauf an wie du deinen Client planst und was da alles auf die Nachricht erfolgen kann/muss/soll.

Also habe lange überlegt und werde für den chat polling benutzen und für die anderen sachen wie zb DU BIST JETZT AM ZUG werde ich callbacks benutzen

Darf man erfahren was für die der ausschlaggebende Grund war auf Polling zu setzen?

Ich würde bei beidem weder Polling noch RMI verwenden. Ich würde beim Server pro Clienten eine 2-Kanal (IP-Port)-Verbindung (einen Sende- und einen Empfänger-Kanal) verwenden evtl. sogar mit Broad- bzw. Multicasts beim Server. Client und Server können so auf ihren Empfangskanälen mit “accept()” warten, bis irgendwas eingeht und nach belieben (also asynchron dazu) senden was, wann und an wen (ok, das gilt nur für den Server) sie wollen.