我们正在尝试使用推送配置的RMI创建一个简单的聊天程序。 该程序在内部网络上工作,但是当试图在外部网络上使用服务器运行程序时,我们收到错误:
java.rmi.ConnectException: Connection refused to host: 192.168.2.24;
Caused by: java.net.ConnectException: Connection timed out: connect
当客户端在“IChatServer”接口上调用方法“Broadcast(String 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 :(得分:0)
对于RMI方式,不要将双方视为客户端 - 服务器,而是remote service
和caller
。
因此caller
需要能够通过TCP连接到remote service
才能执行远程方法调用(RMI)。因此,在您的情况下,必须双方都设置端口转发。由于这可能很麻烦(例如,客户端可能位于非托管的NAT之后 - 就像你的情况一样)最好威胁RMI更像REST服务 - 因此只有一方正在调用remote service
除了转发1099
whitch是RMI注册表端口之外,您还必须转发导出对象使用的端口。 RMI注册表仅包含有关如何连接到实际导出的对象处理程序的信息。