Frage zu RMI

Server registriert ein UnicastRemoteObject (Middleware), Client schickt eine ClientImplementierung an Server, Server speichert Implementierung in Liste, Server geht Liste durch und ruft auf jedem ClientImplementierung eine Methode auf, in Implementierung steht ein System.out.println(); -> System.out. wird beim Server ausgegeben, nicht beim Client -> warum?


        private final ClientProxy clientProxy;
        private final IDClazz idClazz;
        private final String username;
        private final Date date;

        public Elem(ClientProxy cp, IDClazz idClazz, String username, Date date) {
            this.clientProxy = cp;
            this.idClazz= idClazz;
            this.username = username;
            this.date = date;
        }
    }```

Möpp: Gestern funktionierte es noch. Wo ist mein Denkfehler? :stumm:

Danke, Grüße, Cyborg.

Edit: Und ist es richtig, das Server ClientImplementierung (nicht nur das Interface) kennen muss? Und warum muss ich in jedes Interface (außer Server) auch Serializable reinschreiben? Und wenn nur ein double in IDClazz (Interface) steht, muss ich equals() und hashCode() dann auch korrekt überschreiben?
  • zu übertragende Objekte werden mit Serialisierung übertragen, müssen logischerweise Serializable sein,
  • zu double in Interfacen und Methoden deswegen weiß ich nix

allgemein sehe ich an Code und Beschreibung nicht, welche konkreten RMI-Konzepte bestehen und welche Klassen übertragen werden,

als gutes Beispiel mag das SUN/ Oracle-Tutorial dienen:
https://docs.oracle.com/javase/tutorial/rmi/server.html

es braucht ein RMI-Interface, Compute, das muss beiden Seiten bekannt sein, Common-Package,
der Server muss es natürlich implementieren, ComputeEngine, dem Client ist die Implementierung schnuppe

übertragen wird die (serialisierbare) Datenklasse Task, diese ist allgemein in der Mitte stehend, Common-Package,
kann man weder Server noch Client allzusehr zuordnen

der Client erzeugt Task, setzt verschiedene Daten, das Task-Objekt wird an den Server übertragen,
-> nun ist der Task beim Server vorliegend, vom Client vollkommen unabhängig,
wenn beim Server im Task nun eine Ausgabe erfolgt dann selbstverständlich beim Server Ausgabe,
Attribute können geändert werden usw.,

sollte der Task an den Client zurückgehen, dann empfängt der Client ein zweites Taskobjekt mit neuen Attributen,
Client muss sicher aufpassen dass es mit dem zuvor von ihm gesendeten Task zu verknüpfen ist usw.,
im Beispiel wird nur das Ergebnis BigDecimal zurückgesendet

einen anderen Einfluss außer Übertragung von Objekten (und Exceptions) hat weder Server auf Client noch andersrum,
es gibt keine magische System.out.println()-Ausgabe woanders,

natürlich kann man im Task oder sonstigen Rückgabewert Anweisungen hinterlegen:
‘wenn du beim Client bist und der dich um Aktion bittet, dann gib folgendes aus’ usw.,
alles reine Daten nach Modellierung


‘ClientImplementierung’ existiert in meiner Sichtweise nicht unbedingt, nach
http://openbook.galileocomputing.de/javainsel9/javainsel_22_005.htm
kann man das so ansehen dass es statt fertiger Task-Klasse hier nur ein Task-Interface beiden bekannt ist
und die tatsächliche Implementierung in der Tat vom Client an den Server nachgeladen wird,

entscheidende Änderungen ergeben sich dadurch aber nicht,
der Server weiß nicht was die aufgerufenen Methoden tun, ob und welche Attribute sie ändern,
ob sie System.out.println() ausgeben, oder die Festplatte löschen, oder geheime Log-Daten in das dann evtl. zurückgesendete Objekt schreiben,
aber strukturell alles wie zuvor

Um das gehts doch bei RMI, dass man am Client eine Methode aufruft die am Server ausgeführt wird. In deinem Fall beinhaltet diese Methode ein System.out.println. Was ist so seltsam daran, das ist doch der gewünschte Fall?

Also Danke. Ich darf den vorgegebenen Quelltext nicht ins Netz stellen, deshalb nur wat ich gemacht hatte.

Weiß nun, dass Methodenparameter actual wirklich call-by-value übergeben werden (Serialisierung), aber Methodenrückgabetypen wirklich call-by-reference (distributed garbage collector), (nicht wie sonst call-by-value der Referenz).

Der Server soll ein Objekt bekommen, oder der Server soll ein Objekt zurückgeben, worauf der Server eine Methode des Clients aufrufen kann. (Der Client kann ja schon Methode(n) Server aufrufen)

Alle Implementierungen sollen ‚versteckt‘/austauschbar sein, s. d. nur mit den Interfaces hantiert wird, nach möglichkeit. :frowning: Versteht ihr wat ich meine? Mehr darf ich dazu nicht bekanntgeben.

ich habe nicht viel verstanden, z.B. auch nicht ob noch eine Frage offen ist,

alles zu ‘darf nicht bekannt gegeben werden’ sehe ich aber als großen Witz,
wenn es um allgemeine RMI-Implementierungen geht,
man kann immer irgendein anderes Beispielprogramm bauen, ‘Remote Taschenrechner mit austauschbarer/ versteckter Berechnungsmethode’
je weniger ist aber vielleicht auch besser

Was das Überschreiben von hashCode und equals angeht, so ist das davon abhängig, ob die Implementierung mutable (hat das double Setter?) oder nicht ist. Bei Mutables macht ein expliziter HashCode aufgrund des veränderbaren Inhalts nämlich nur sehr wenig Sinn.

[OT]Womit eigentlich wieder eine Diskussion über Sinn und Unsinn des Contracts fällig wär, dass wenn man equals überschreibt, auch hashCode überschreiben sollte. Sinniger wäre es, wenn man diesen Contract dahingehend erweitern sollte, das dieses tatsächlich nur bei Imutables wirklich Sinn macht (dadurch sind auch nur Imutables in HashSets/-Maps sinnvoll) und man ihn brechen muss, wenn man Mutables in solchen Sets/Maps verwenden will. Für letzteren Fall hat man 3 Möglichkeiten:

  1. Man überschreibt hashCode und equals wie vorgesehen und verwendet diese Mutables nur in IdentityHashSets/-Maps oder
  2. Man überschreibt nur equals wodurch eine Verwendung in jedwedem anderen HashSet gestattet wird. Besser aber wäre, wenn man statt equals explizit eine andere Vergleichsmethode implementiert (etwa “matches” o-ä.).[/OT]

Das double ist immutable.

Implementierung:


    private final double id = Math.random();

    @Override
    public boolean equals(Object obj) {
        if (obj == null || !(obj instanceof MyClazzImpl)) {
            return false;
        }
        return this.id == ((MyClazzImpl) obj).id;
    }

    @Override
    public int hashCode() {
        int hash = 5;
        hash = 37 * hash + (int) (Double.doubleToLongBits(this.id) ^ (Double.doubleToLongBits(this.id) >>> 32)); // hat IDE bei geholfen
        return hash;
    }
}```

MyClazz ist `extends Remote, Serializable` (`Remote` nicht wirklich sinnvoll).

Das mit "IdentityHashSets/-Maps" hab ich verstanden. Blöderweise ist eine Verwendung in Sets, etc. erst mal nicht "vorgesehen".

 @SlaterB : Das Probl ist, der Server kann, auf der "Referenz" (hier Serialisierung) der Client-Klasse keine Methode(n) "remote" aufrufen. Warum?

ich habe keinen Anspruch darauf, alle Möglichkeiten von RMI zu kennen, aber aus meiner bisherigen Sicht kann ich sagen:
warum sollte der Server das können?
möglich sind natürlich Ideen, aber das RMI-Modell (so wie ich es kenne) ist überschaubar und ausreichend:
der Client fragt beim Server an, sendet dabei Daten, der Server agiert bei sich und sendet Daten zurück,
klein fein ideal, dein Punkt kommt dabei nicht vor,

vielleicht bei ‘Callback’
https://docs.oracle.com/cd/E13211_01/wle/rmi/callbak.htm

oder wie schon mal geschrieben: der Server könnte bei Bedard ja Informationen in der Rückantwort ablegen, was zurück beim Client getan werden muss, das passiert dann nach der Rückkehr,
wenn weiter zu kommunizieren ist neue Anfrage,

Es geht um ein Chat- System. Danke für den/deinen Link. Der Server hat eine Liste mit Clients. Der Server möchte alle Clients “benachrichtigen” (String), wenn eine neue/geprüfte Nachricht eingetroffen ist, ohne das Client(s) alle 10 Sekunden prüfen, und Client extra einen Port listen muss. So ungefähr. Quelltext darf ich wirklich nicht bekannt geben.

obligatorisch in so einem Thread ist ja eigentlich auch die Werbung für RMI-Alternative SIMON von @tuxedo
SIMON – Wikipedia
inklusive Feature

Bidirektionale Methodenaufrufe über Netzwerke hinweg
Hat ein Client eine Verbindung zu einem SIMON Server aufgebaut, so kann der Server denselben, bereits offenen Kommunikationskanal nutzen, um Methoden auf Clientseite aufzurufen.

Darum geht’s, alsbald “established”, soll diese auch genutzt werden, Nachrichten zurückzuschicken.
Architektur nicht zu aufwändig.

Also für simples Messaging (Chat/Messenger) brauchts kein RMI geschweige denn ein Bidirektionales wie z.B. SIMON.