-1

乍一看,这似乎是一个基本的网络问题——但我认为情况并非如此。似乎 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);
  }
}
4

2 回答 2

1

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

java.rmi.server.hostname

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

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

您的服务器配置了 IP 地址192.168.0.110,因此,这就是 RMI 注册表报告的内容。RMI 注册表不知道您想通过某个其他 IP 地址(即可公开路由的 IP 地址110.142.83.167- 也无法合理地知道防火墙是否正在执行网络地址转换)来访问机器。

对话是这样的:

  • WAN 客户端连接到位于 的 RMI 注册表110.142.83.167
  • 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. (或者,您可以在客户端计算机上使用主机文件条目,但如果客户端计算机的数量很大,这在管理上会很麻烦)。

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

于 2016-10-18T05:49:59.257 回答
0

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

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

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

于 2018-02-15T10:01:13.110 回答