【问题标题】:Localhost-only RMI?仅限本地主机的 RMI?
【发布时间】:2012-03-07 15:26:44
【问题描述】:

我有一个启动第二个 JVM 的项目。目前我正在使用 RMI 在两者之间进行通信。在我自己的机器上运行良好。

我需要能够在我无权更改防火墙规则的 Windows 7 机器上部署此项目。

注册表(从第一个 JVM 中的高任意端口启动)被阻止打开这些机器上的服务器套接字。

有没有办法限制 RMI 只监听本地连接;这样 Windows 防火墙会很酷吗?

或者,是否有一个很好的替代 IPC 方法,只需要很少的功能更改?

干杯。

【问题讨论】:

  • 这就是 Web 服务(在 8080 端口上工作)受到欢迎的原因。
  • 我不确定这会有什么帮助?我可以在两者之间打开一个本地 http 连接,但在那个阶段我最好只在套接字上运行一个对象流?

标签: java ipc localhost rmi firewall


【解决方案1】:

这比一开始看起来更棘手。想要的是限制注册表正在侦听的 IP 地址,而不是端口。问题是 RMI Registry 实现程序 (rmiregistry) 实际上并没有提供任何机制来限制它侦听的 IP 地址;它总是监听每个可用的网络接口。只有两种实际的机制可以限制这一点:

  1. 使用防火墙规则。老实说,这是一种正常的技术,但它需要在部署期间进行配置。
  2. 使用特殊版本的 RMI 注册表将限制应用于正确的 IP 地址(即 localhost127.0.0.1),因为 Windows 不会抱怨只能被从本地机器到达。

第二个选项是我将勾勒出来的。这实际上很简单,因为您可以将大部分复杂性委托给现有的类。

import java.io.IOException;
import java.net.*;
import java.rmi.server.*;
import java.rmi.registry.LocateRegistry;

public class RestrictedRMIRegistry implements RMIServerSocketFactory {
    public static void main(String... args) throws IOException {
        int port = (args.length == 0 ? 1099 : Integer.parseInt(args[0], 10));
        RMIClientSocketFactory csf = RMISocketFactory.getDefaultSocketFactory();
        RMIServerSocketFactory ssf = new RestrictedRMIRegistry();

        LocateRegistry.createRegistry(port, csf, ssf);
    }

    public ServerSocket createServerSocket(int port) throws IOException {
        // Tricky bit; make a server socket with bound address
        return new ServerSocket(port, 0, InetAddress.getLocalHost());
    }
}

这与普通的rmiregistry 实现之间的唯一区别是它使用了客户端和服务器套接字工厂的默认值。

【讨论】:

  • 正是我想要的。
  • 我发现这对于类似的问题非常有帮助,出于安全目的,我想将 RMI 限制为 localhost。但是,我发现我还需要限制端口 1098 套接字。这可以通过向远程类的构造函数提供相同的套接字工厂来完成,例如公共类 RemoteStatistics 扩展 UnicastRemoteObject { private RemoteStatistics() throws RemoteException { super(1098, null, RestrictableRMIRegistry.getInstance()); }
  • 抱歉,我是一个使用 SO 注释标记的菜鸟,我正在努力让该代码正确格式化。
【解决方案2】:

在启动注册表(或您的方案中涉及的任何其他 Java 进程)时,尝试将 java.rmi.server.hostname 属性设置为 127.0.0.1

【讨论】:

  • 这不是一个坏主意,但它不会影响注册表,只会影响从设置属性的 JVM 导出的其他远程存根,因为注册表存根是在本地构建的,而不是远程获取的。限制 SocketPermission 'accept' 的 .policy 文件是另一种可能性。
  • 嗯,你是对的。当我使用该设置运行rmiregistry 时,它仍然会打开一个完全开放的端口。 :–( 我知道如何解决,但需要编写代码。
  • java.rmi.server.hostname 不控制监听端口,它控制写入存根的内容。 LocateRegistry.getRegistry() 从您给它的 host:port 本地构造一个 Registry 存根,因此在注册表的 JVM 上设置 java.rmi.server.hostname 不会对该存根产生任何影响。要获取注册表或任何其他远程对象,以打开绑定到 127.0.0.1 的端口,必须指定 RMIServerSocketFactory,以便在导出时这样做。
  • @EJP 是的,当时正在把它写成一个单独的答案......
【解决方案3】:

较好的替代方法是通过 HTTP 调用 Web 服务,该服务通常对出站连接开放。

问题在于入站连接。我相信“正确”的架构是当部署在防火墙后面的进程通过第三个进程相互通信时 - 安装在入站 HTTP 连接不受限制的地方的服务器。因此,防火墙后面的 2 个组件只执行到服务器的出站 HTTP 连接。

【讨论】:

  • 我不需要这样做。系统的所有部分都在一台机器上运行,不需要外部资源。问题是 windows 防火墙阻止了我用于本地 IPC 的 rmiregistry。
猜你喜欢
  • 2012-09-23
  • 1970-01-01
  • 2012-11-26
  • 1970-01-01
  • 2014-05-31
  • 1970-01-01
  • 1970-01-01
  • 2013-01-10
  • 2011-01-09
相关资源
最近更新 更多