[英]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 服務器 PC,但隨后沒有進入 RMI 服務器本身。
我的第一個猜測是嘗試使用“Java 控制面板”之類的東西,並可能調整可能限制 RMI 流量的安全設置 - 但我無法識別任何此類開關。
任何人都可以提供任何線索嗎?
任何建議或指導將不勝感激。
(已編輯,添加更多詳細信息...)
更多信息如下...
堆棧跟蹤如下...
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
- 也無法合理地知道防火牆是否在進行網絡地址轉換)。
對話是這樣的:
110.142.83.167
RMI 注冊表。Foo
交談192.168.0.110:<some port>
到達Foo
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.