RMI服务器(似乎)忽略WAN上的连接

时间:2016-10-17 11:20:40

标签: java rmi wan

乍一看,这似乎是一个基本的网络问题 - 但我 认为 并非如此。似乎Java本身就是"忽略" RMI连接。

Windows 10 PC上的所有Java 8u101。

我们有一个非常成熟和强大的分布式Java应用程序,它通过LAN上的RMI进行通信 对于在LAN上运行我们的应用程序多年的客户来说,完全没有问题。 同样的应用程序也连接到共享数据库(在与RMI服务器相同的服务器" PC上)。

我们的一位客户最近在距离100米远的地方建立了一座新建筑,他们的两处房屋通过广域网连接。但是,远程站点上的Java客户端无法连接到Java RMI服务器。

似乎所有网络本身都可以如下......

    局域网上的
  • 一切正常运行
  • 非RMI没问题:
    • 从远程位置我们可以运行不同的数据库客户端并成功连接到数据库服务器(与RMI服务器在同一台PC上)
  • 来自客户端的RMI端口似乎没问题
    • 使用远程位置的telnet客户端,我们可以建立与RMI端口的连接
  • RMI端口似乎连接在服务器PC上:
    • 在运行Java RMI服务器的PC上,我们可以通过" netstat -an"来看到连接。显示已建立的连接来自适当的WAN IP地址。

这表明(对我而言)连接正在到达正确的位置,并且没有被错误配置或防火墙或任何东西阻止。它似乎得到了#34;到RMI服务器PC,但后来没有到达RMI服务器本身。

我的第一个猜测是尝试使用类似" Java控制面板"并且可能调整可能限制RMI流量的安全设置 - 但我无法识别任何此类切换。

有人可以提供任何线索吗?

  • 验证连接是否到达Java的任何方式?
  • 可能是Java安全性在它传递给RMI服务器之前阻止它吗?

非常感谢任何建议或指导。

(编辑,添加更多细节......)

更多信息如下......

  • 在LAN内,服务器PC称为192.168.0.110
  • 从远程位置(通过WAN),服务器PC称为110.142.83.167
  • 远程客户端似乎获得了RMI服务器对象
  • 堆栈跟踪(详见下文)" Connection拒绝主持人: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);
  }
}

ServerRMIObject ...

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

2 个答案:

答案 0 :(得分:1)

来自https://docs.oracle.com/javase/8/docs/technotes/guides/rmi/javarmiproperties.html

  

java.rmi.server.hostname

     

此属性的值表示应与本地创建的远程对象的远程存根关联的主机名字符串,以允许客户端调用远程对象上的方法。 此属性的默认值是本地主机的IP地址,在&#34; dotted-quad&#34;格式。

RMI注册表向客户端报告IP地址(或主机名)以及客户端可以连接到的端口以调用远程对象。默认情况下,它使用本地主机的地址。

您的服务器配置了IP地址192.168.0.110,因此,这是RMI注册表报告的内容。 RMI注册表不知道您想要通过其他IP地址(即可公共路由110.142.83.167)访问计算机 - 也不能合理地知道防火墙是否正在进行网络地址转换。 / p>

谈话是这样的:

  • WAN客户端连接到110.142.83.167的RMI注册表。
  • WAN客户端问:我想知道如何与对象Foo交谈
  • RMI注册表报告:您可以Foo
  • 192.168.0.110:<some port>联系
  • WAN客户端尝试连接192.168.0.110:<some port>,但无法访问该计算机

您可以将java.rmi.server.hostname设置为显式值(例如110.142.83.167),但请注意,然后所有客户端将尝试使用该IP地址连接到远程对象

解决此问题的一种方法是使用主机名和拆分DNS系统,外部客户端将主机名解析为110.142.83.167,但内部客户端将主机名解析为192.168.0.110。 (或者,您可以在客户端计算机上使用hosts文件条目,但如果客户端计算机的数量很大,则会在管理上变得麻烦。)

另请注意,如果您未将远程对象明确绑定到特定端口,则将使用临时端口 - 因此您需要防火墙才能访问所有端口。通过将远程对象绑定到特定端口,可以将防火墙配置为仅允许该端口通过(加上注册表端口)。

答案 1 :(得分:0)

当我们将RMI服务器计算机升级到WINDOWS 10时,我们遇到了类似的问题。

此异常是由于运行服务器的Windows10的Windows防火墙不允许通过TCP协议传输到端口。

要为TCP启用Windows10防火墙,我们需要按照以下步骤操作: 1.打开控制面板 2. Windows防火墙 - &gt;高级设置 3.单击入站规则 4.在右栏 - &gt;新规则选项 5.创建端口规则并同时创建TCP和UDP规则 - 本地端口1099 /所有端口 6.在操作部分中,单击“允许连接” 7.检查所有规则适用的地方