2016-11-08 14 views
0

プッシュ設定でRMIを使用して簡単なチャットプログラムを作成しようとしています。 プログラムは、内部ネットワーク上で動作しますが、外部ネットワーク上のサーバでプログラムを実行しようとしていたとき、私たちはエラーを取得:外部ネットワーク上のRMI Chatプログラムのプッシュ設定が機能しない

java.rmi.ConnectException: Connection refused to host: 192.168.1.13; 
Caused by: java.net.ConnectException: Connection timed out: connect 

クライアントがメソッド「放送(文字列を呼び出したときにエラーが発生しましたs) 'を入力します。 このメソッドは、サーバー上にあり、サーバー上のリスナーとして購読している他のクライアントを呼び出します。

クライアントはサーバーに接続できます。レジストリからバインディングを取得し、サーバーからメソッドを呼び出すことができます。

しかし、サーバーがクライアントからメソッドを呼び出そうとすると、このエラーが発生します。

サーバーでは、ポート1099が転送され、ポート1099はファイアウォールで許可されます。

これを可能にする方法はありますか(RMIを使用して)? または、クライアント側のポートを転送する必要がありますか?

サーバー:

try {  
      String theIp = serverHostExternalIp; 

      System.setProperty("java.rmi.server.hostname", theIp); 

      //Implemented this so no random ports will be used 
      RMISocketFactory.setSocketFactory(new FixedPortRMISocketFactory()); 

      registry = LocateRegistry.createRegistry(PORT_NUMBER); 

      publisher = new RemotePublisher(); 
      publisher.registerProperty(BINDING_NAME); 


      UnicastRemoteObject.unexportObject(server, true); 
      UnicastRemoteObject.exportObject(server, PORT_NUMBER); 

      UnicastRemoteObject.unexportObject(publisher, true); 
      UnicastRemoteObject.exportObject(publisher, PORT_NUMBER); 


      registry.rebind(BINDING_NAME, server); 
      registry.rebind(PUBLISH_NAME, publisher); 
     } catch (RemoteException ex) { 
      System.err.println("[Server] Cannot bind student administration"); 
      System.err.println("[Server] RemoteException: " + ex.getMessage()); 
     } 

IChatServer:

public synchronized void tryConnect(String s, IChatClient client) throws RemoteException {   
    System.out.println("[Server] User connected: " + s); 
} 

public synchronized void broadcast(String s) throws RemoteException { 
    // When this line is called, no errors occur, and the string is printed correctly. 
    System.out.println("[Message] " + s); 

    //on this line, the server tries to reach to all the clients (all listeners) 
    //This line of code will generate an error. 
    publisher.inform(BINDING_NAME, null, s); 
} 

クライアント:

try { 
       registry = LocateRegistry.getRegistry(ipAddress, PORT_NUMBER);    

       mycs = (IChatServer) registry.lookup(BINDING_NAME); 

       //This method is located on the server and is called without errors. 
       mycs.tryConnect(userid, this);      

       publisher = (IRemotePublisherForListener) registry.lookup(PUBLISH_NAME);      
       publisher.subscribeRemoteListener(this, BINDING_NAME); 

      } catch (RemoteException ex) { 
       System.err.println("[Client] Cannot lookup or subscribe publisher"); 
       System.err.println("[Client] RemoteException: " + ex.getMessage()); 
       registry = null; 
      } catch (NotBoundException e) { 
       System.err.println("[Client] Cannot lookup or subscribe publisher"); 
       System.err.println("[Client] NotBoundException: " + e.getMessage()); 
       registry = null; 
      } 
+0

2ウェイ接続がありますか?クライアントはサーバ上のメソッドを呼び出すことができますか? – Antoniossss

+0

@Antoniossssはい、チャットプログラムを作成する最良の方法ではないかもしれません。私は、クライアントがメッセージを送信するサーバーに、そしてサーバーがそのメッセージを他のすべてのクライアントにブロードキャストするようにクライアントに指示する必要があります。少なくとも、それは私がそれを理解しているものです。 – Wilmz

+0

一般にPUSHアーキテクチャが必要ですが、RMIは一般的なPULLです。あなたがXMPPのようなチャットのようなコミュニケーション(そしてもっと!)のために既存のテクノロジーを自由に使うのはなぜですか?過去に私はXMPPに基づいてチャットアプリケーションを作成し、メッセージブローカーとしてOpenFireサーバーを使用しました。 メッセージキューを使用して、チャットアプリケーションの目的でPUSHアーキテクチャを実現することもできます。 – Antoniossss

答えて

0

RMI方式の場合は、クライアント・サーバーではなく、むしろremote serviceとしての側面を考えるといけませんcaller

したがって、callerは、Remote Method Invocation(RMI)を実行するために、TCP経由でremote serviceに接続できる必要があります。したがって、あなたのケースでは、ポート転送を両方向に賢明に設定する必要があります。これは面倒なことがあります(例えば、クライアントはあなたのように管理されていないNATの後ろにいる可能性があります)。RMIサービスのようにRMIを脅かす方が良いです。エクスポートされたオブジェクトが使用するポートも転送する必要があります。 RMIレジストリには、実際にエクスポートされたオブジェクトハンドラに接続する方法に関する情報しか保持されません。

関連する問題