2016-11-08 37 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)'在接口'IChatServer' 此方法位于服务器上,并调用服务器上订阅为侦听器的其他客户端。

我们的客户端可以连接到服务器。它可以从注册表获取绑定并从服务器调用方法。

但是,当服务器试图从客户端调用一个方法时,我们得到这个错误。

在服务器上,端口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。保证io重新发明轮子,为什么不使用已有的和免费使用像XMPP这样的聊天通讯技术(以及更多!)的技术?在过去,我已经成功创建了基于XMPP的聊天应用程序,并使用OpenFire服务器作为消息代理。 您也可以使用消息队列来实现PUSH架构,以实现聊天应用程序的目的。 – Antoniossss

回答

0

对于RMI方式,不认为双方的客户端 - 服务器的,而是remote servicecaller

所以caller需要能够通过TCP连接到remote service为了执行远程方法调用(RMI)。所以在你的情况下,端口转发必须在双方都设置好。因为这可能很麻烦(例如,客户端可能在NAT之后,不受管理 - 就像你的情况一样),最好是威胁RMI更像REST服务 - 所以只有一方叫remote service

除了转发1099 whitch是RMI注册表端口,您还需要转发导出对象使用的端口。 RMI注册表只保存关于如何连接到实际导出的对象处理程序的信息。