2012-02-16 75 views
1

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

我需要能够部署在Windows 7机器这个项目,我没有权限修改防火墙规则。

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

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

另外,有将需要很少的功能变化的良好替代IPC的方法?

干杯。

+0

这就是Web服务(在8080端口上工作)获得普及的原因。 – 2012-02-16 08:28:51

+0

我不知道这将如何帮助?我可以在两者之间打开一个本地http连接,但是在那个阶段,我最好只是在套接字上运行一个对象流呢? – FlightOfStairs 2012-02-16 10:00:02

回答

3

这比第一次看起来更复杂。需要的是限制注册表正在监听的IP 地址,但不限制端口。问题是RMI注册实现程序(rmiregistry)实际上并没有提供任何机制来限制它监听的IP地址;它总是监听每个可用的网络接口。只有两种实际的限制机制:

  1. 使用防火墙规则。这是一种正常的技术,但它需要在部署过程中进行配置。
  2. 使用适用的限制,以恰到好处的IP地址(即localhost127.0.0.1)RMI注册的一个特殊版本,因为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实现之间唯一的区别是,它使用了客户端和服务器套接字工厂的默认值。

+0

正是我在找的 – FlightOfStairs 2012-02-22 14:38:12

+0

我发现这对于一个类似的问题非常有帮助,我为了安全目的想限制RMI到本地主机,但是我发现我还需要限制端口1098套接字。做完b y将这个相同的套接字工厂提供给远程类的构造器,例如 公共类RemoteStatistics扩展了UnicastRemoteObject { 私人RemoteStatistics()将抛出RemoteException { 超(1098, 空, RestrictableRMIRegistry.getInstance()); } – Fanjita 2014-04-29 11:16:48

+0

对不起,我是一个有SO注释标记的noob,我努力让这些代码格式正确。 – Fanjita 2014-04-29 11:23:16

0

好的替代方法称为HTTP上的Web服务,通​​常用于出站连接。

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

+0

我不需要这样做。系统的所有部分都在一台机器上运行,并且不需要外部资源。问题是Windows防火墙阻止了rmiregistry,这是我用于本地IPC的。 – FlightOfStairs 2012-02-16 09:48:34

0

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

+0

这不是一个坏主意,但它不会影响注册表,只会从其中设置属性的JVM导出其他远程存根,因为注册表存根本地构建,而不是远程获取。限制SocketPermission“接受”的.policy文件是另一种可能性。 – EJP 2012-02-22 09:26:20

+0

嗯,你说得对。当我使用该集合运行'rmiregistry'时,它仍然打开一个敞开的端口。 :-(我知道如何解决,但是需要一点点写,因为它需要代码 – 2012-02-22 09:47:47

+0

'java.rmi.server.hostname'不控制监听端口,它控制写入存根。'LocateRegistry.getRegistry()'从你提供的host:port本地构造一个Registry stub,所以在注册表的JVM上对java.rmi.server.hostname的设置不会对该stub产生任何影响。获取注册表或任何其他远程对象来打开绑定到127.0.0.1的端口时,必须指定一个在导出时会这样做的'RMIServerSocketFactory'。 – EJP 2012-02-22 09:57:33