没有注册表通过RMI连接服务器

5

我有一个可以通过 RMI 连接的服务对象。目前我正在这样做:

服务器

Registry r = LocateRegistry.createRegistry(1234);
r.bind("server", UnicastRemoteObject.exportObject(remoteServer, 0));

客户端

RemoteServer s = LocateRegistry.getRegistry("example.com", 1234).lookup("server");

服务器上的注册表只有一个用途,即链接到单个服务器对象。我想我可能会在服务器上完成这一操作:
UnicastRemoteObject.exportObject(remoteServer, 1234);

那么我该如何从客户端连接到服务器对象呢?

3个回答

13
RMI Registry是为了解决RMI引导问题而存在的,这个问题在于你只能通过远程方法调用获得一个远程存根,但要执行远程方法调用,则需要一个远程存根。由LocateRegistry.getRegistry()提供的Registry引用解决了这个问题(如果您正在使用该API,则内部使用它来调用Naming.lookup())。[请注意,此存根不是通过远程方法获得的:它是使用您提供的主机:端口本地合成的。如果它们不正确,您直到使用注册表存根之前都不会发现错误。]
您有几种选择来解决RMI引导问题:
  1. 使用RMI Registry。
  2. 通过LDAP提供程序使用JNDI使用LDAP服务器。
  3. 使用UnicastRemoteObject,序列化导出对象时获取的存根,然后使用共享文件、套接字或sneakernet使存根可用于客户端。
  4. 使用RMI Activation;序列化注册可激活对象时获得的存根,并将其与客户端应用程序一起分发到所有客户端。从存根分发的角度来看,这比(3)要简单得多,因为存根在应用程序的生命周期内保持不变,而在(3)中,您必须在每次导出时重新分发存根。
您可以看到,Registry肯定是最简单的选项。请注意,您只需要使用它来解决引导问题。一旦您有了一个存根,您自己的应用程序远程方法就可以返回更多对象:您不需要在Registry中使用多个远程对象。您可以将其视为远程对象工厂。

我再次遇到了这个问题(http://stackoverflow.com/questions/11399408/simple-entry-point-for-single-rmi-service),这一次不能使用注册表。我可以使用方法3,但是如果客户端拥有服务的接口、主机/端口,它是否可以自己合成一个存根? - Bart van Heukelom
理论上可以,实际上不太行。为什么你不能使用注册表? - user207421
很好的提示(3),只需将序列化的存根以某种方式传输到客户端即可。从文档中从未理解过它是如此简单。现在,Zookeeper也是一个不错的选择。 - Harald
对于(3),值得注意的是,设置系统属性java.rmi.server.hostname似乎是获取存根的唯一方法,该存根可以从一台机器连接到另一台机器,而不仅仅是在本地主机上。 - Harald
只有在导出主机的DNS配置错误或存在公共/私有IP地址问题时才会出现这种情况。 - user207421

1

虽然不是不可能,但并不是非常实用,因为注册表将导出对象的存根对象传递给客户端(请参见http://www.developer.com/print.php/3455311)。如果您没有其他机制,那么您将被卡住。在分布式系统中使用注册表还有其他好处,因此我实际上建议出于其他原因保留它(位置透明性等)。


Vista:那不正确,也不是你提供的链接所说的。注册表只解决引导问题:您只能获得远程存根作为远程方法的结果,而对于此,您需要一个远程存根... - user207421
Vista:不,引导程序问题是向客户端提供初始存根对象,正如您的链接所说。您说了“类”,这完全是错误的。注册表不提供类。您关于“新存根类”和“新对象实例”的第二个声明也没有任何意义。 - user207421
@EJB:如果问题在于类与对象的使用,我同意你的观点并已经进行了更正。我的重点在于存根的起源以及注册表的必要性,这显然是问题的核心。顺便说一句,我无法编辑上面的评论,所以我将其删除。 - kvista

0

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接