You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

无法与远程服务器RMI Registry建立连接的问题排查

排查RMI远程连接超时/拒绝问题的关键步骤

我来帮你梳理几个RMI跨网络部署时最容易踩的坑,结合你的代码和Azure环境来看,这些点大概率能解决你的问题:

1. 先确认Registry端口的一致性

看你的服务器代码,构造函数接收了int port参数,但创建Registry时用的是硬编码的PORT常量:

registry = LocateRegistry.createRegistry(PORT);

而客户端连接时用的是SERVER_PORT常量,这两个值必须完全匹配!如果服务器用的是默认1099端口,客户端也要用1099;如果自定义了端口,两边的常量值必须统一。

另外,这里有个高频坑:RMI默认会给远程对象分配随机端口,哪怕你开放了Registry的端口,客户端调用方法时需要连接这个随机端口,而Azure防火墙没开放这些端口,就会超时。这个问题后面单独说解决办法。

2. 修复Naming.bind的URL格式错误

你的服务器代码里这段写法是错的:

Naming.bind(address, this);

Naming.bind要求传入标准的RMI协议URL,格式是rmi://<主机IP>:<端口>/<服务名>。比如你的公网IP是13.xx.xx.xx,Registry端口是1099,服务名是REGISTRY_NAME,应该写成:

Naming.bind("rmi://" + address + ":" + PORT + "/" + REGISTRY_NAME, this);

不过其实你已经通过registry.bind(REGISTRY_NAME, this)把对象绑定到Registry了,完全没必要重复用Naming.bind,重复绑定反而可能引发隐藏异常,建议直接删掉Naming.bindNaming.rebind的代码块,只用Registry的bind/rebind逻辑就够了。

3. 把java.rmi.server.hostname设为Azure公网IP

你异常里显示的目标IP是10.0.0.6,这是虚拟机的内网IP,外部客户端根本访问不到!必须把java.rmi.server.hostname设置为Azure虚拟机的公网IP地址(你可以在Azure门户的虚拟机详情页找到这个IP),替换掉构造函数传入的address参数。

4. 修复安全策略的启动参数错误

你的启动命令里的安全策略参数写法不对:

-Djava.security.policy=java.security.AllPermission

java.security.policy需要指向一个策略文件,或者用特殊语法临时开放所有权限。正确的两种写法:

  • 方法一(推荐,适合测试和生产):创建一个rmi.policy文件,内容如下:
    grant {
        permission java.security.AllPermission;
    };
    
    然后启动命令改为:
    java -cp flyway-core-6.0.8.jar:mssql-jdbc-7.4.1.jre8.jar:mysql-connector-java-8.0.18.jar:. -Djava.security.policy=rmi.policy kmalfa.RmiServer
    
  • 方法二(仅快速测试用):用==-(两个等号)直接允许所有权限:
    java -cp flyway-core-6.0.8.jar:mssql-jdbc-7.4.1.jre8.jar:mysql-connector-java-8.0.18.jar:. -Djava.security.policy==- kmalfa.RmiServer
    

错误的策略配置可能导致RMI无法正确暴露远程对象,哪怕服务器看起来启动成功。

5. 固定RMI远程对象的端口(解决随机端口问题)

前面提到的随机端口问题,你可以通过启动参数强制固定这个端口:
在服务器启动命令里添加:

-Djava.rmi.server.port=<你指定的固定端口,比如1100>

然后在Azure的网络安全组(NSG)里,把这个固定端口和Registry端口(比如1099)一起加入入站规则,允许外部访问。这样客户端调用方法时就会连接这个固定端口,不会再出现超时。

6. 验证服务器端的Registry注册状态

你可以在服务器代码里加一段打印,确认服务是否真的注册成功:

import java.util.Arrays;

// 在绑定完成后添加
String[] boundServices = registry.list();
System.out.println("已注册的服务列表:" + Arrays.toString(boundServices));

如果能看到REGISTRY_NAME在列表里,说明Registry注册是正常的。也可以在虚拟机上用telnet localhost <Registry端口>测试本地是否能连通Registry。

7. 最后确认Azure的网络配置

  • 确保虚拟机的**网络安全组(NSG)**入站规则,已经开放了Registry端口和你固定的RMI对象端口,并且源IP允许你的客户端IP(或者临时设为所有IP测试)。
  • 确认虚拟机的公网IP是静态IP,避免重启后IP变化导致客户端连接失败。

按照上面的步骤逐一排查,应该就能解决你的连接问题了。

内容的提问来源于stack exchange,提问作者Narrangel

火山引擎 最新活动