如何使 RMI 服务器同时为本地客户端(在同一网络内)和外部客户端工作
How to make a RMI server work for both local clients (within the same network) and external clients
我是 Java 和 RMI 的新手,我决定尝试在我的家用计算机上为聊天客户端设置我自己的服务器(仅用于学习目的,没有实际用途) ) 。总而言之,我使用套接字连接来处理消息,使用 RMI 来进行服务器和客户端之间的通信。问题是我正在使用路由器,我希望客户端同时用于外部连接和内部连接(例如我的笔记本电脑 - 连接到与服务器相同的路由器)。
我的publicip是:109.99.33.251
我本地的ip地址是:196.168.1.9
问题是,如果我将 java.rmi.server.hostname 设置为
- 服务器本地ip:
- 一切都按预期工作,但仅当从本地计算机访问服务器时。
- 从外部机器访问时,只有套接字连接,rmi 查找抛出连接被拒绝:连接超时。 (我想提一下,我 99% 确定 RMI (1099) 和服务器 (5000) 的端口转发设置正确)
- Server public ip: 一切正常,但仅适用于外部机器。
- 当尝试使用服务器的本地 ip 从本地计算机连接时,套接字连接正常,但 rmiregistry 查找方法失败。
- 当使用服务器的 public ip 从本地计算机连接时,RMIregistry 和套接字都无法连接。
我的猜测是路由器的问题。我认为它不支持 NAT loopback(使用它的 public ip 从 LAN 组件访问服务器)因为它永远无法连接到服务器它是来自本地机器的 public ip,即使端口转发设置正确(它在为 RMI 和套接字连接进行外部连接时也有效)。
我能做些什么来完成这项工作吗?
编辑:
在服务器端,我在服务器启动后立即设置 System.setProperty("java.rmi.server.hostname","109.99.33.251");
然后我:
LocateRegistry.createRegistry(1099);
然后我绑定对象:
MyRemote stub= new Communicator();
registry = LocateRegistry.getRegistry();
registry.bind("comm", stub);
其中 MyRemote 是扩展 Remote 接口的接口,并且
通讯器是:
public class Communicator extends UnicastRemoteObject implements MyRemote
{
public Communicator() throws RemoteException
{
super(Registry.REGISTRY_PORT);
System.out.println("I've created the host");
}
//the methods in the MyRemote
}`
对于我使用的套接字:
ServerSocket serverSock = new ServerSocket(5000);
while(true)
{
Socket clientSocket = serverSock.accept();
ClientHandler handler =new ClientHandler(clientSocket);
clients.add(handler);
Thread t = new Thread(handler);
t.start();
System.out.println("got a connection");
}
对于客户端查找:
service=(MyRemote) Naming.lookup("rmi://"+serverIp+"/comm");
和套接字连接 Socket socket=new Socket(serverIp,new Integer(serverPort));
serverIp
保存服务器的 public ip 或本地 ip,具体取决于我之前介绍的情况。 serverPort
是 5000
为了清楚起见,我希望客户端在本地和外部机器上都能工作,所以我正在寻找一种方法来绑定远程对象并设置连接以使两者都能工作(如果可能的话)。
注意:对不起,我是网络、java 和这个网站的新手,所以请不要介意我在提问时犯的错误。提前致谢!
最终编辑:我已经就此联系了我的 ISP,他们说路由器有最新的固件版本,它根本不支持 NAT 环回。
不幸的是,Oracle/Sun RMI 实现在这方面略有问题。有一个不必要的深层假设,即所有客户端都可以看到一个 IP 地址。您必须将 java.rmi.server.hostname
设置为 NAT 外部的 public IP 地址,并且内部客户端必须能够使用该地址。
我是 Java 和 RMI 的新手,我决定尝试在我的家用计算机上为聊天客户端设置我自己的服务器(仅用于学习目的,没有实际用途) ) 。总而言之,我使用套接字连接来处理消息,使用 RMI 来进行服务器和客户端之间的通信。问题是我正在使用路由器,我希望客户端同时用于外部连接和内部连接(例如我的笔记本电脑 - 连接到与服务器相同的路由器)。
我的publicip是:109.99.33.251
我本地的ip地址是:196.168.1.9
问题是,如果我将 java.rmi.server.hostname 设置为
- 服务器本地ip:
- 一切都按预期工作,但仅当从本地计算机访问服务器时。
- 从外部机器访问时,只有套接字连接,rmi 查找抛出连接被拒绝:连接超时。 (我想提一下,我 99% 确定 RMI (1099) 和服务器 (5000) 的端口转发设置正确)
- Server public ip: 一切正常,但仅适用于外部机器。
- 当尝试使用服务器的本地 ip 从本地计算机连接时,套接字连接正常,但 rmiregistry 查找方法失败。
- 当使用服务器的 public ip 从本地计算机连接时,RMIregistry 和套接字都无法连接。
我的猜测是路由器的问题。我认为它不支持 NAT loopback(使用它的 public ip 从 LAN 组件访问服务器)因为它永远无法连接到服务器它是来自本地机器的 public ip,即使端口转发设置正确(它在为 RMI 和套接字连接进行外部连接时也有效)。
我能做些什么来完成这项工作吗?
编辑:
在服务器端,我在服务器启动后立即设置 System.setProperty("java.rmi.server.hostname","109.99.33.251");
然后我:
LocateRegistry.createRegistry(1099);
然后我绑定对象:
MyRemote stub= new Communicator();
registry = LocateRegistry.getRegistry();
registry.bind("comm", stub);
其中 MyRemote 是扩展 Remote 接口的接口,并且
通讯器是:
public class Communicator extends UnicastRemoteObject implements MyRemote
{
public Communicator() throws RemoteException
{
super(Registry.REGISTRY_PORT);
System.out.println("I've created the host");
}
//the methods in the MyRemote
}`
对于我使用的套接字:
ServerSocket serverSock = new ServerSocket(5000);
while(true)
{
Socket clientSocket = serverSock.accept();
ClientHandler handler =new ClientHandler(clientSocket);
clients.add(handler);
Thread t = new Thread(handler);
t.start();
System.out.println("got a connection");
}
对于客户端查找:
service=(MyRemote) Naming.lookup("rmi://"+serverIp+"/comm");
和套接字连接 Socket socket=new Socket(serverIp,new Integer(serverPort));
serverIp
保存服务器的 public ip 或本地 ip,具体取决于我之前介绍的情况。 serverPort
是 5000
为了清楚起见,我希望客户端在本地和外部机器上都能工作,所以我正在寻找一种方法来绑定远程对象并设置连接以使两者都能工作(如果可能的话)。
注意:对不起,我是网络、java 和这个网站的新手,所以请不要介意我在提问时犯的错误。提前致谢!
最终编辑:我已经就此联系了我的 ISP,他们说路由器有最新的固件版本,它根本不支持 NAT 环回。
不幸的是,Oracle/Sun RMI 实现在这方面略有问题。有一个不必要的深层假设,即所有客户端都可以看到一个 IP 地址。您必须将 java.rmi.server.hostname
设置为 NAT 外部的 public IP 地址,并且内部客户端必须能够使用该地址。