乍一看,这似乎是一个基本的网络问题——但我认为情况并非如此。似乎 Java 本身“忽略”了 RMI 连接。
Windows 10 PC 上的所有 Java 8u101。
我们有一个相当成熟和健壮的分布式 Java 应用程序,它通过 LAN 上的 RMI 进行通信。
对于多年来在他们的 LAN 上运行我们的应用程序的客户来说,完全没有问题。这个相同的应用程序还连接到一个共享数据库(在与 RMI 服务器相同的“服务器”PC 上)。
我们的一位客户最近在 100 米外建立了一座新建筑,他们的两个场所通过 WAN 连接。但是,远程站点的 Java 客户端无法连接到 Java RMI 服务器。
似乎所有网络本身都可以,如下所示....
- 在 LAN 上一切正常运行
- 非 RMI 可以:
- 从远程位置,我们可以运行不同的数据库客户端并成功连接到数据库服务器(与 RMI 服务器在同一台 PC 上)
- 从客户端看 RMI 端口似乎没问题
- 在远程位置使用 telnet 客户端,我们可以建立到 RMI 端口的连接
- RMI 端口似乎连接到服务器 PC:
- 在运行 Java RMI 服务器本身的 PC 上,我们可以通过“netstat -an”见证连接,它显示已建立的连接来自适当的 WAN IP 地址。
这表明(对我而言)连接正在到达正确的位置,并且没有被错误配置或防火墙或任何东西阻止。它似乎“进入”了 RMI 服务器 PC,但随后没有进入 RMI 服务器本身。
我的第一个猜测是尝试使用“Java 控制面板”之类的东西,也许可以调整可能限制 RMI 流量的安全设置 - 但我无法识别任何此类开关。
任何人都可以提供任何线索吗?
- 有什么方法可以验证连接是否到达 Java?
- 在它传递到 RMI 服务器之前,它可能是一个阻止它的 Java 安全性吗?
任何建议或指导将不胜感激。
(编辑,添加更多细节......)
更多信息如下...
- 在 LAN 中,服务器 PC 被称为 192.168.0.110
- 从远程位置(通过 WAN),服务器 PC 被称为 110.142.83.167
- 远程客户端似乎获得了 RMI 服务器对象
- 堆栈跟踪(详情如下)有“连接拒绝主机:192.168.0.110;”
- 所以似乎对它是哪个IP地址感到困惑。客户端请求110.142.83.167,但服务器认为是192.168.0.110
堆栈跟踪如下...
2016-10-18 15:02:11,123 [S38P4][43983 ][AWT-EventQueue-0] WARN StackTraceLogger log: StackTraceLogger ------- INFO=ClientRMIObject.connectToSentry(): RemoteException: sentryIP=110.142.83.167<<
StackTraceLogger ------ Throwable.MSG=Connection refused to host: 192.168.0.110; nested exception is:
java.net.ConnectException: Connection timed out: connect< Throwable=java.rmi.ConnectException: Connection refused to host: 192.168.0.110; nested exception is:
java.net.ConnectException: Connection timed out: connect
StackTraceLogger.START TRACE .................................
sun.rmi.transport.tcp.TCPEndpoint.newSocket(Unknown Source)
sun.rmi.transport.tcp.TCPChannel.createConnection(Unknown Source)
sun.rmi.transport.tcp.TCPChannel.newConnection(Unknown Source)
sun.rmi.server.UnicastRef.invoke(Unknown Source)
java.rmi.server.RemoteObjectInvocationHandler.invokeRemoteMethod(Unknown Source)
java.rmi.server.RemoteObjectInvocationHandler.invoke(Unknown Source)
com.sun.proxy.$Proxy13.registerWithSentry(Unknown Source)
com.my.co.package.ClientRMIObject.connectToSentry(ClientRMIObject.java:198)
遵循代码的超级精简版本(无样板等)......
在 RMI 服务器...
// auto called at server on startup ...
public final class MyServer {
public final static int SRVR_PORT = 21099;
public final static String LOOKUP_NAME = "MyLookupName";
public MyServer() {
java.rmi.registry.Registry reg = java.rmi.registry.LocateRegistry.createRegistry(SRVR_PORT);
ServerRMIObject srvrRmiObj = new ServerRMIObject();
reg.rebind(LOOKUP_NAME, srvrRmiObj);
}
}
服务器RMI对象...
public final class ServerRMIObject extends java.rmi.server.UnicastRemoteObject {
private List<ClientRMIObject> clients = ...
public ServerRMIObject() throws java.rmi.RemoteException {
super(MyServer.SRVR_PORT);
}
public void registerWithSrvr(ClientRMIObject client) {
logger.info("This line is never run when called from remote location");
clients.add(client);
}
// example method ...
public void broadcastToClients(Delivery d) {
for (ClientRMIObject client : clients) {
client.receiveFromSrvr(d);
}
}
}
在每个 RMI 客户端...
public final class ClientRMIObject extends java.rmi.server.UnicastRemoteObject {
private final int CLIENT_PORT = 21099;
private final String SRVR_FROM_LAN = "//192.168.0.110:"+MyServer.SRVR_PORT+"/"+MyServer.LOOKUP_NAME;
private final String SRVR_FROM_WAN = "//110.142.83.167:"+MyServer.SRVR_PORT+"/"+MyServer.LOOKUP_NAME;
private ServerRMIObject rmiSrvr = null;
public ClientRMIObject() {
super(CLIENT_PORT);
}
// auto called at client on startup
public void start() {
if (VIA_LAN) {
rmiSrvr = java.rmi.Naming.lookup(SRVR_FROM_LAN);
} else if (VIA_WAN) {
rmiSrvr = java.rmi.Naming.lookup(SRVR_FROM_WAN);
}
// this has been successful to here.
// the following throws an exception ...
// java.rmi.ConnectException: Connection refused to host: 192.168.0.110;
// please see more exception details above
rmiSrvr.registerWithSrvr(this);
}
// example method ...
public void receiveFromSrvr(Delivery d) {
....
}
// example broadcast from one client to all clients ...
public void broadcastToClients(Delivery d) {
rmiSrvr.broadcastToClients(d);
}
}