Wie kann ich sicherstellen, dass RMI nutzt nur einen bestimmten Satz von ports?

StackOverflow https://stackoverflow.com/questions/56687

  •  09-06-2019
  •  | 
  •  

Frage

In unserer Anwendung verwenden wir RMI für die Kommunikation zwischen client und server auf sehr unterschiedliche Weise:

  1. Pushen von Daten vom server an den client angezeigt werden.
  2. Senden control Daten vom client an den server.
  3. Rückrufe von diesen Nachrichten Steuern-code-Pfade, erreichen Sie wieder vom server zum client (sidebar Hinweis - dies ist ein Nebeneffekt, dass einige legacy-code und ist nicht unsere langfristige Absicht).

Was wir gerne tun würde, ist sicherzustellen, dass alle unsere RMI-code wird nur eine bekannte angegebenen inventory of ports.Dies beinhaltet die Registrierung port (allgemein erwartet, 1099), server-port und alle ports, die aus der Rückrufe.

Hier ist, was wir bereits wissen:

  1. LocateRegistry.getRegistry(1099) ein, oder Suchen Sie.createRegistry(1099) wird sichergestellt, dass die Registrierung ist in hören auf 1099.
  2. Mit den Konstruktor von UnicastRemoteObject / exportObject statische Methode mit einer port-argument geben Sie den port des Servers ein.

Diese Punkte sind auch in diesem Sun forum posten.

Was wir nicht wissen ist:wie stellen wir sicher, dass die client-verbindungen zurück an den server, die aus der Rückrufe wird nur eine Verbindung auf einer bestimmten port anstatt säumigen auf eine anonyme port?

EDIT:Hinzugefügt eine längliche Antwort fasst meine Erkenntnisse und wie wir das problem gelöst.Ich hoffe, dies wird helfen, alle anderen mit ähnlichen Problemen.

ZWEITER EDIT:Es stellt sich heraus, dass in meiner Anwendung ist, scheint es eine race-Bedingung in meinem Erstellung und änderung der Buchse Fabriken.Ich wollte dem Benutzer erlauben, zu überschreiben, zu meiner Standard-Einstellungen in ein Beanshell-Skript.Leider scheint es, dass mein Skript ausgeführt wird, deutlich nach den ersten sockel entsteht durch die Fabrik.Als ein Ergebnis, ich bin immer ein mix von ports aus der Menge der defaults " und " Benutzer-Einstellungen.Mehr Arbeit erforderlich sein wird, die außerhalb des Bereichs dieser Frage, aber ich dachte, ich würde es darauf hin als ein Punkt von Interesse für andere, die möglicherweise zu beschreiten diesen Gewässern irgendwann....

War es hilfreich?

Lösung

Sie können dies mit einer benutzerdefinierten RMI Socket Factory.

Die Buchse Fabriken erstellen, um die Buchsen für RMI auf die Verwendung sowohl in der Client- und Server-Ende so, wenn Sie Ihre eigene Sie haben volle Kontrolle über die verwendeten Ports schreiben. Die Client-Fabriken werden auf dem Server erstellt, serialisiert und schickte dann an den Client herunter, die recht ordentlich ist.

Hier ist ein Führer bei Sun sagen Ihnen, wie zu tun es.

Andere Tipps

Sie brauchen keine Steckdose Fabriken für diese oder sogar mehrere Ports. Wenn Sie die Registrierung von Ihrem Server JVM fangen können Sie Port 1099 für alles verwenden, und in der Tat das ist, was standardmäßig geschehen wird. Wenn Sie überhaupt nicht die Registrierung beginnen, wie es in einem Client-Callback-Objekt, können Sie Port 1099 zur Verfügung stellen, wenn sie zu exportieren.

Der Teil Ihrer Frage über ‚die Client-Verbindungen zurück an den Server von Rückrufen resultierenden‘ machen keinen Sinn. Sie unterscheiden sich nicht von den ursprünglichen Client-Verbindungen zu dem Server, und sie werden den gleichen Server-Port (s) verwendet werden.

Zusammenfassung der langen Antwort unten: Um das Problem zu lösen, das ich hatte (Server und Callback-Ports zu beschränken an jedem Ende der RMI-Verbindung), musste ich zwei Paare von Client- und Server-Socket-Fabriken erstellen

.

Lange Antwort folgt:

Unsere Lösung für das Callback-Problem hatte im Wesentlichen aus drei Teilen. Die erste war die Aufgabe Umhüllung, die die Fähigkeit benötigt, um anzugeben, dass es im Vergleich zu einem Client-Server-Verbindung verwendet wurde, für einen Server zum Client-Callback verwendet wird. eine Erweiterung von UnicastRemoteObject Mit gab uns die Möglichkeit, die Client- und Server-Socket-Fabriken zu spezifizieren, die wir verwenden wollten. der beste Ort, um die Buchse Fabriken zu sperren ist jedoch im Konstruktor des entfernten Objekts.

public class RemoteObjectWrapped extends UnicastRemoteObject {
// ....
private RemoteObjectWrapped(final boolean callback) throws RemoteException {
  super((callback ? RemoteConnectionParameters.getCallbackPort() : RemoteConnectionParameters.getServerSidePort()),
        (callback ? CALLBACK_CLIENT_SOCKET_FACTORY : CLIENT_SOCKET_FACTORY),
        (callback ? CALLBACK_SERVER_SOCKET_FACTORY : SERVER_SOCKET_FACTORY));
}
// ....
}

So gibt das erste Argument der Teil, auf dem die Objektanforderungen erwartet, während der zweite und der dritte die Buchse Fabriken angeben, die an beiden Enden der Verbindung verwendet werden, wird diese entfernte Objekt antreibt.

Da wir die Ports, die von der Verbindung verwendet beschränken wollten, mussten wir die RMI Socket-Fabriken erweitern und die Ports sperren. Hier sind einige Skizzen unserer Server- und Client-Fabriken:

public class SpecifiedServerSocketFactory implements RMIServerSocketFactory {
/** Always use this port when specified. */
private int serverPort;
/**
 * @param ignoredPort This port is ignored.  
 * @return a {@link ServerSocket} if we managed to create one on the correct port.
 * @throws java.io.IOException
 */
@Override
public ServerSocket createServerSocket(final int ignoredPort) throws IOException {
    try {
        final ServerSocket serverSocket = new ServerSocket(this.serverPort);
        return serverSocket;
    } catch (IOException ioe) {
        throw new IOException("Failed to open server socket on port " + serverPort, ioe);
    }
}
// ....
}
Hinweis

, dass die Server-Socket-Factory oben stellt sicher, dass nur der Hafen, die Sie zuvor angegeben wird jemals von dieser Fabrik verwendet werden. Die Client-Socket-Factory hat mit der entsprechenden Buchse Fabrik gekoppelt werden (oder Sie verbinden nie).

public class SpecifiedClientSocketFactory implements RMIClientSocketFactory, Serializable {
/** Serialization hint */
public static final long serialVersionUID = 1L;
/** This is the remote port to which we will always connect. */
private int remotePort;
/** Storing the host just for reference. */
private String remoteHost = "HOST NOT YET SET";
// ....
/**
 * @param host The host to which we are trying to connect
 * @param ignoredPort This port is ignored.  
 * @return A new Socket if we managed to create one to the host.
 * @throws java.io.IOException
 */
@Override
public Socket createSocket(final String host, final int ignoredPort) throws IOException {
    try {
        final Socket socket = new Socket(host, remotePort);
        this.remoteHost = host;
        return socket;
    } catch (IOException ioe) {
        throw new IOException("Failed to open a socket back to host " + host + " on port " + remotePort, ioe);
    }
}
// ....
}

Also, das einzige, was noch Ihre Zwei-Wege-Verbindung zu erzwingen auf dem gleichen Satz von Ports zu bleiben ist eine gewisse Logik zu erkennen, dass Sie zurück an den Client-Seite aufrufen. In dieser Situation, so stellen Sie sicher, dass Ihre Factory-Methode für das ferne Objekt ruft die RemoteObjectWrapper Konstruktor bis oben mit den Callback-Parametern auf true gesetzt.

Ich habe verschiedene Probleme wurde mit einer RMI-Server / Client-Architektur Implementierung mit Client-Rückrufen. Mein Szenario ist, dass sowohl die Server- und Client ist hinter Firewall / NAT. Am Ende bekam ich eine voll funktionsfähige Implementierung. Hier sind die wichtigsten Dinge, die ich getan habe:

Server Side, Lokale IP: 192.168.1.10. Public (Internet) IP 80.80.80.10

Auf der Firewall / Router / Local Server PC offen Port 6620. Auf der Firewall / Router / Local Server PC offen Port 1099. Auf dem Router / umleiten NAT eingehende Verbindungen auf Port 6620 zu 192.168.1.10:6620 Auf dem Router / NAT umleiten eingehende Verbindungen auf Port 1099 bis 192.168.1.10:1099

Im eigentlichen Programm:

System.getProperties().put("java.rmi.server.hostname", IP 80.80.80.10);
MyService rmiserver = new MyService();
MyService stub = (MyService) UnicastRemoteObject.exportObject(rmiserver, 6620);
LocateRegistry.createRegistry(1099);
Registry registry = LocateRegistry.getRegistry();
registry.rebind("FAManagerService", stub);

Client-Seite, Lokale IP: 10.0.1.123 Public (Internet) IP 70.70.70.20

Auf der Firewall / Router / Local Server PC offen Port 1999. Auf dem Router / NAT umleiten eingehende Verbindungen auf Port 1999 bis 10.0.1.123:1999

Im eigentlichen Programm:

System.getProperties().put("java.rmi.server.hostname", 70.70.70.20);
UnicastRemoteObject.exportObject(this, 1999);
MyService server = (MyService) Naming.lookup("rmi://" + serverIP + "/MyService ");

Hoffe, das hilft. Iraklis

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top