10

このアプリケーションでは、クライアント/サーバー通信にRMIを非常に異なる方法で使用しています。

  1. 表示するサーバーからクライアントにデータをプッシュします。
  2. クライアントからサーバーへの制御情報の送信。
  3. これらの制御メッセージからのコールバックは、サーバーからクライアントに戻るコードパスです(補足説明-これは一部のレガシーコードの副作用であり、長期的な意図ではありません)。

私たちがやりたいのは、すべてのRMI関連のコードが既知の指定されたポートのインベントリのみを使用するようにすることです。これには、レジストリポート(通常は1099と予想されます)、サーバーポート、およびコールバックから生じるすべてのポートが含まれます。

これが私たちがすでに知っていることです:

  1. LocateRegistry.getRegistry(1099)またはLocate.createRegistry(1099)は、レジストリが1099でリッスンしていることを確認します。
  2. UnicastRemoteObjectコンストラクター/exportObject静的メソッドをport引数とともに使用すると、サーバーポートが指定されます。

これらのポイントは、このSunフォーラムの投稿でも取り上げられています。

わからないのは、コールバックの結果としてサーバーに戻るクライアント接続が、デフォルトで匿名ポートではなく、指定されたポートでのみ接続されるようにするにはどうすればよいでしょうか。

編集:私の発見と問題をどのように解決したかを要約した長い答えを追加しました。うまくいけば、これは同様の問題を抱えている他の人の助けになるでしょう。

2番目の編集:私のアプリケーションでは、ソケットファクトリの作成と変更に競合状態があるようです。ユーザーがBeanshellスクリプトのデフォルト設定を上書きできるようにしたかったのです。残念ながら、最初のソケットがファクトリによって作成された後、スクリプトが大幅に実行されているようです。その結果、デフォルトのセットとユーザー設定からポートが混在しています。この質問の範囲外であるより多くの作業が必要になるでしょうが、私はそれをある時点でこれらの水域を踏まなければならないかもしれない他の人たちの興味のあるポイントとして指摘したいと思いました。

4

4 に答える 4

4

これは、カスタム RMI Socket Factory で行うことができます。

ソケット ファクトリは、RMI がクライアント エンドとサーバー エンドの両方で使用するソケットを作成するため、独自のソケットを作成すると、使用するポートを完全に制御できます。クライアント ファクトリはサーバー上で作成され、シリアル化されてからクライアントに送信されます。

これは、その方法を説明する Sun のガイドです。

于 2008-09-11T14:36:40.987 に答える
2

このためのソケット ファクトリや複数のポートは必要ありません。サーバー JVM からレジストリを開始する場合は、すべてにポート 1099 を使用できます。実際、これがデフォルトで行われます。クライアント コールバック オブジェクトのように、レジストリをまったく起動しない場合は、エクスポート時にポート 1099 を指定できます。

「コールバックに起因するサーバーへのクライアント接続」に関する質問の部分は意味がありません。サーバーへの元のクライアント接続と同じであり、同じサーバー ポートを使用します。

于 2016-05-20T22:25:28.773 に答える
1

以下の長い答えの要約:私が抱えていた問題(RMI接続の両端でサーバーとコールバックポートを制限する)を解決するには、クライアントとサーバーのソケットファクトリの2つのペアを作成する必要がありました。

より長い答えが続きます:

コールバックの問題に対する私たちの解決策は、基本的に3つの部分で構成されていました。1つ目は、オブジェクトのラッピングであり、クライアントからサーバーへの接続に使用されているのか、サーバーからクライアントへのコールバックに使用されているのかを指定する機能が必要でした。の拡張機能を使用すると、使用するUnicastRemoteObjectクライアントおよびサーバーソケットファクトリを指定できるようになりました。ただし、ソケットファクトリをロックダウンするのに最適な場所は、リモートオブジェクトのコンストラクタです。

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));
}
// ....
}

したがって、最初の引数はオブジェクトが要求を予期している部分を指定し、2番目と3番目はこのリモートオブジェクトを駆動する接続の両端で使用されるソケットファクトリを指定します。

接続で使用されるポートを制限したかったので、RMIソケットファクトリを拡張してポートをロックダウンする必要がありました。これが私たちのサーバーとクライアントの工場のスケッチです:

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);
    }
}
// ....
}

上記のサーバーソケットファクトリは、以前に指定したポートのみがこのファクトリによって使用されることを保証することに注意してください。クライアントソケットファクトリは、適切なソケットファクトリとペアにする必要があります(そうしないと、接続できなくなります)。

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);
    }
}
// ....
}

したがって、双方向接続を同じポートセットに維持するために残っているのは、クライアント側にコールバックしていることを認識するロジックだけです。そのような状況では、リモートオブジェクトのファクトリメソッドが、コールバックパラメーターをtrueに設定してRemoteObjectWrapperコンストラクターを一番上に呼び出すことを確認してください。

于 2008-11-19T19:39:28.583 に答える
0

クライアント コールバックを使用して、RMI サーバー/クライアント アーキテクチャを実装する際にさまざまな問題が発生しました。私のシナリオは、サーバーとクライアントの両方がファイアウォール/NAT の背後にあるというものです。最後に、完全に機能する実装を取得しました。これが私がした主なことです:

サーバー側、ローカル IP: 192.168.1.10。パブリック (インターネット) IP 80.80.80.10

ファイアウォール/ルーター/ローカル サーバー PC でポート 6620 を開きます。ファイアウォール/ルーター/ローカル サーバー PC でポート 1099 を開きます。ルーター/NAT でポート 6620 の着信接続を 192.168.1.10:6620 にリダイレクトします。ルーター/NAT で着信をリダイレクトしますポート 1099 から 192.168.1.10:1099 への接続

実際のプログラムでは:

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);

クライアント側、ローカル IP: 10.0.1.123 パブリック (インターネット) IP 70.70.70.20

ファイアウォール/ルーター/ローカル サーバー PC でポート 1999 を開きます。ルーター/NAT で、ポート 1999 の着信接続を 10.0.1.123:1999 にリダイレクトします。

実際のプログラムでは:

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

お役に立てれば。イラクリス

于 2010-03-16T14:25:23.513 に答える