java - 如何使 RMI 服务器同时为本地客户端(同一网络内)和外部客户端工作

标签 java sockets networking rmi nat

我对 Java 和 RMI 还很陌生,我决定尝试在我的家用计算机上为聊天客户端设置自己的服务器(仅用于学习目的,没有真正的用途)。总而言之,我使用套接字连接来发送消息,并使用 RMI 来进行服务器和客户端之间的通信。问题是我正在使用路由器,并且我希望客户端能够同时用于外部连接和内部连接(例如我的笔记本电脑 - 连接到与服务器相同的路由器)。

<小时/>

我的公网IP是:109.99.33.251
我的本地IP地址是:196.168.1.9
问题是,如果我将 java.rmi.server.hostname 设置为

  • 服务器本地IP:
    • 一切都按预期运行,但仅限于从本地计算机访问服务器时。
    • 当从外部机器访问时,只有套接字连接,rmi查找抛出连接拒绝:连接超时。 (我想提一下,我 99% 确定 RMI (1099) 和服务器 (5000) 的端口转发都已正确设置)
  • 服务器公共(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);

然后我绑定(bind)对象:

MyRemote stub= new Communicator();
registry = LocateRegistry.getRegistry();
registry.bind("comm", stub);

其中 MyRemote 是扩展 Remote 接口(interface)的接口(interface), 通讯器是:

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

<小时/>

为了让自己清楚,我希望客户端能够在本地和外部计算机上工作,因此我正在寻找一种方法来绑定(bind)远程对象并设置连接以使两者都工作(如果可能的话)。

注意:很抱歉,我对网络、java 和这个网站都很陌生,所以请不要介意我在提问时犯的错误。预先感谢您!

最终编辑:我已就此事联系了我的 ISP,他们说路由器具有最新的固件版本,而且它根本不支持 NAT 环回。

最佳答案

不幸的是,Oracle/Sun RMI 实现在这方面略有缺陷。有一个不必要的深层假设,即所有客户端都可见一个 IP 地址。您必须将 java.rmi.server.hostname 设置为 NAT 外部的公共(public) IP 地址,并且内部客户端必须能够使用该地址。

关于java - 如何使 RMI 服务器同时为本地客户端(同一网络内)和外部客户端工作,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31394031/

相关文章:

java - 正则表达式replaceAll如何包含行分隔符

java - 如何使用字符串作为参数来表示 Java 中的对象?

java - 无法执行 dex : Multiple dex files define Lcom/google/android/gms/analytics/internal/Command

java - Qt server/Java Client通讯问题

linux - 通过单个套接字发送的 UDP 数据包是否保证按顺序发送?

安卓网络

java - 在 wifi 网络上发现客户端

java - 使用 Java 将地理位置坐标渲染为图像

android - 如何在 Android 中打开端口?

debugging - 在 Docker 中启用 Wildfly 域模式下的调试 - 端口已在使用中