RMI ConnectionRefused schon bei Server-binding

Ir3n!cus

Aktives Mitglied
Ich habe ein merkwürdiges Problem mit RMI. Vor etwa zwei Monaten hatte ich die Implementierung des RMI interface bereits lauffähig. Das Server-binding hat funktioniert und ein anderes Java Programm konnte sich darauf verbinden und die Methoden des Server aufrufen. Heute wollte ich die Implementierung weiter ausarbeiten und "plötzlich" lässt sich keine Verbindung zur Registry mehr herstellen. Das "registry.rebind(url, server);" liefert jetzt ein "java.rmi.ConnectException: Connection refused".

Zum debuggen habe ich mal versucht, die Registry Einträge mit einer simplen Schleife auszugeben.
Selbst da kommt "java.rmi.ConnectException: Connection refused", also schon beim Lesen der Registry.

Irgendwie scheint die JVM auf ihre eigene Registry nicht zugreifen zu dürfen.
Das scheint keines der üblichen Probleme zu sein, die man bei Google zu RMI findet. Hat jemand eine Idee?

Java:
public static String registerRmiServer(MyRmiServer server, int port) throws RemoteException {
        String url = String.format("rmi://localhost:%s/%s", port, INTERFACENAME); // INTERFACENAME = "MeinServer", port = 4711
       
        Registry registry;
        try {
            try {
                registry = LocateRegistry.getRegistry(port);
            } catch(RemoteException ex) {
                registry = LocateRegistry.createRegistry(port);
            }
           
           
            // -------- zum debug zusätzlich eingefügt ---------
            System.out.println("listing start");
            for (String entry : registry.list()) {
                System.out.println(entry);
            }
            System.out.println("listing end");
            // ------------------------------------------------------
           
           
        } catch(RemoteException ex) {
            throw new RemoteException(String.format("RMI Registry creation failed for: %s", url), ex);
        }
       
        try {
            registry.rebind(url, server);
        } catch(RemoteException ex) {
            throw new RemoteException(String.format("RMI Server binding failed for: %s", url), ex);
        }
       
        return url;
    }
 
Zuletzt bearbeitet:
Beste Antwort
Das Problem ist, getRegistry erzeugt keine Exception, wenn die entfernte Registry nicht vorhanden ist. Brauchst nen Singleton:

Java:
import java.io.Serial;
import java.io.Serializable;
import java.rmi.NotBoundException;
import java.rmi.Remote;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import java.util.Arrays;

public class RMIExample {
    private static boolean created = false;

    public static class RunnableImpl implements Remote, Runnable, Serializable {
        @Serial
        private static final long serialVersionUID = 1L;
        private int i = 1;

        @Override
        public void run() {
            System.out.println("Hello, world! " + i++)...
Java:
public class RmiExample {
    public static final String UNIQUE_BINDING_NAME = "double.string";
    public static Registry registry;
    public static Thread CLIENT_THREAD = new Thread(new Runnable() {

        @Override
        public void run() {
            try {
                DoubleString doubleString = (DoubleString) registry.lookup(UNIQUE_BINDING_NAME);
                System.out.println(doubleString.doubleString("hello"));
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }
    });

    public static void main(String[] args) {

        try {
            // create registry
            registry = LocateRegistry.createRegistry(2099);
            // the service to export
            final DoubleStringImpl service = new DoubleStringImpl();

            // create remote object stub to bind to registry
            Remote stub = UnicastRemoteObject.exportObject(service, 0);
            registry.bind(UNIQUE_BINDING_NAME, stub);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }

        CLIENT_THREAD.start();
    }
}


interface DoubleString extends Remote {
    String doubleString(String str) throws RemoteException;
}

class DoubleStringImpl implements DoubleString {
    public String doubleString(String str) throws RemoteException {
        return str + str;
    }
}
 
Ich habe alle Kombinationen der url durch, mit-ohne Protokollname, mit-ohne Host, mit-ohne Port, usw.
Immer mit dem gleichen Ergebnis. Außerdem hat es ja schon mit dieser Form des "Binding-Namen" funktioniert.

Ich würde auch nicht erwarten, dass es an der url liegt.
Das Auslesen der Registry wirft ja den gleichen Fehler. Dafür brauche ich keine url.
 
Zuletzt bearbeitet:
Das Problem ist, getRegistry erzeugt keine Exception, wenn die entfernte Registry nicht vorhanden ist. Brauchst nen Singleton:

Java:
import java.io.Serial;
import java.io.Serializable;
import java.rmi.NotBoundException;
import java.rmi.Remote;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import java.util.Arrays;

public class RMIExample {
    private static boolean created = false;

    public static class RunnableImpl implements Remote, Runnable, Serializable {
        @Serial
        private static final long serialVersionUID = 1L;
        private int i = 1;

        @Override
        public void run() {
            System.out.println("Hello, world! " + i++);
        }
    }

    public static Registry createAndRebind(String host, int port, String name) throws RemoteException {
        if (!created) {
            System.out.println("Creating RMI registry on " + host + ":" + port);
            Registry registry = LocateRegistry.createRegistry(port);
            registry.rebind(name, new RunnableImpl());
            created = true;
            return registry;
        }
        System.out.println("Using existing RMI registry on " + host + ":" + port);
        return LocateRegistry.getRegistry(host, port);
    }

    public static void main(String[] args) throws RemoteException, NotBoundException {
        Registry registry = createAndRebind("localhost", 4699, "Runnable");

        Arrays.stream(registry.list()).forEach(System.out::println);
        ((RunnableImpl) registry.lookup("Runnable")).run();

        ((RunnableImpl) createAndRebind("localhost", 4699, "Runnable").lookup("Runnable")).run();
    }
}

Btw. Ich nehme an, dass du nicht immer "localhost" verwenden wirst ... ansonsten wäre auch null als host für localhost möglich.
 
Beste Antwort
Das Problem ist, getRegistry erzeugt keine Exception, wenn die entfernte Registry nicht vorhanden ist.
Das ist ja mal spannend. Ich will doch den Zustand der Registry nicht in meinem Programm verwalten.
Das soll sie mal schön selbst tun. Gerade bei einer Funktion die von verschiedenen Programmen genutzt wird. 🙄
Ich habe daher erstmal nur die Reihenfolge ausgetauscht.

Java:
Registry registry;
try {
    try {
        registry = LocateRegistry.createRegistry(port);
    } catch(RemoteException ex) {
        registry = LocateRegistry.getRegistry(port);
    }
       
} catch(RemoteException ex) {
    throw new RemoteException(String.format("RMI Registry creation failed for: %s", url), ex);
}

In den Javadocs steht ja leider sehr ungenau, was zu Exceptions führt.
Da steht auch nicht was genau passiert, wenn die Registry bei "create" schon da ist....
wird sie überschrieben? wird sie erweitert? wird das Internet gelöscht?

Und das "getRegistry" ein valides Objekt zurückgibt, selbst wenn es die Registry auf dem Port nicht gibt, ist auch merkwürdig.

Btw. Ich nehme an, dass du nicht immer "localhost" verwenden wirst ... ansonsten wäre auch null als host für localhost möglich.
Doch bleibt es. Das wird ein API nur für lokale Kommunikation zwischen Programmen.
Aber auch ein guter Tipp. Das habe ich so auch nicht aus der Doku rausgelesen.
 
Zuletzt bearbeitet:
Der Code kann nicht richtig sein:
Java:
Registry registry;
try {
    try {
        registry = LocateRegistry.createRegistry(port);
    } catch(RemoteException ex) {
        registry = LocateRegistry.getRegistry(port);
    }
          
} catch(RemoteException ex) {
    throw new RemoteException(String.format("RMI Registry creation failed for: %s", url), ex);
}
In Java werden Exceptions nicht zur Steuerung des Programmflusses verwendet. Wenn ich mir das Tutorial von Oracle anschaue, wird das dort auch nicht so gemacht. Weder Server noch Client verwenden dort: LocateRegistry.createRegistry
 
In Java werden Exceptions nicht zur Steuerung des Programmflusses verwendet
Stimmt, das sollte man, wenn möglich, vermeiden.

Das ist ja mal spannend. Ich will doch den Zustand der Registry nicht in meinem Programm verwalten.
Das soll sie mal schön selbst tun. Gerade bei einer Funktion die von verschiedenen Programmen genutzt wird.
Eigentlich brauchst du mindestens zwei Anwendungen, wobei die erste nur die RMI Registry anlegt. Die anderen holen sich die dann mit getRegistry und schauen mit lookup nach, ob alles geht.

Das kann alles auf localhost geschehen, aber muss es nicht. Wenn nicht localhost, dann musst du auch an die Sicherheit denken.^^ Gilt, ähnlich wie RDP, als nicht sicher. 😉 (Kenne da den neusten Stand aber nicht genau)

Edit: Gerade mal geschaut, RMI over SSH tunneling wäre sicher, wenn es nicht auf localhost beschränkt is.
 

Neue Themen


Zurück
Oben