簡體   English   中英

RMI 服務器(似乎)忽略 WAN 上的連接

[英]RMI Server (seems to) ignore connections over WAN

乍一看,這似乎是一個基本的網絡問題 - 但我認為事實並非如此。 Java 本身似乎“忽略”了 RMI 連接。

Windows 10 PC 上的所有 Java 8u101。

我們有一個非常成熟和健壯的分布式 Java 應用程序,它通過 LAN 上的 RMI 進行通信。
對於在他們的 LAN 上運行我們的應用程序多年的客戶來說,完全沒有問題。 這個相同的應用程序還連接到一個共享數據庫(在與 RMI 服務器相同的“服務器”PC 上)。

我們的一位客戶最近在大約 100 米外建立了一座新大樓,他們的兩個場所通過 WAN 連接。 但是,遠程站點的 Java 客戶端無法連接到 Java RMI 服務器。

似乎所有網絡本身都可以,如下所示......

  • 在局域網上一切正常運行
  • 非 RMI 也可以:
    • 我們可以從遠程位置運行不同的數據庫客戶端並成功連接到數據庫服務器(與 RMI 服務器在同一台 PC 上)
  • 從客戶端看 RMI 端口似乎沒問題
    • 在遠程位置使用 telnet 客戶端,我們可以建立到 RMI 端口的連接
  • RMI 端口似乎連接到服務器 PC:
    • 在運行 Java RMI 服務器本身的 PC 上,我們可以通過“netstat -an”見證連接,它顯示從適當的 WAN IP 地址到達的已建立連接。

這表明(對我而言)連接正在到達正確的位置,並且沒有被錯誤配置或防火牆或任何東西阻止。 它似乎“進入”了 RMI 服務器 PC,但隨后沒有進入 RMI 服務器本身。

我的第一個猜測是嘗試使用“Java 控制面板”之類的東西,並可能調整可能限制 RMI 流量的安全設置 - 但我無法識別任何此類開關。

任何人都可以提供任何線索嗎?

  • 有什么方法可以驗證連接是否到達 Java?
  • 可能是 Java 安全在它傳遞到 RMI 服務器之前阻止了它?

任何建議或指導將不勝感激。

(已編輯,添加更多詳細信息...)

更多信息如下...

  • 在局域網內,服務器 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);
  }
}

來自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 地址訪問機器(即公共可路由的110.142.83.167 - 也無法合理地知道防火牆是否在進行網絡地址轉換)。

對話是這樣的:

  • WAN 客戶端連接到位於110.142.83.167 RMI 注冊表。
  • WAN 客戶端詢問:我想知道如何與對象Foo交談
  • RMI 注冊表報告:您可以在192.168.0.110:<some port>到達Foo
  • 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 文件條目,但如果客戶端機器的數量很大,這在管理上會變得很麻煩)。

另請注意,如果您沒有明確地將遠程對象綁定到特定端口,則將使用臨時端口——因此您將需要防火牆允許訪問所有端口。 通過將遠程對象綁定到特定端口,您的防火牆可以配置為僅允許該端口通過(加上注冊端口)。

當我們將 RMI 服務器機器升級到 WINDOWS 10 時,我們遇到了類似的問題。

此異常是由於運行服務器的 Windows10 的 Windows 防火牆不允許流量通過 TCP 協議傳輸到端口。

要為 TCP 啟用 windows10 防火牆,我們需要按照以下步驟操作: 1. 打開控制面板 2. Windows 防火牆 -> 高級設置 3. 單擊入站規則 4. 在右欄中 -> 新規則選項 5. 制定端口規則並創建TCP 和 UDP 規則,都在 - 本地端口 1099 /所有端口 6. 在操作部分,單擊“允許連接” 7. 在規則適用的地方檢查所有內容

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM