Java RMI连接使用的是哪个端口?

27

我可以知道Java RMI连接使用的端口是什么吗?

如果我想使用RMI连接将Java客户端应用程序连接到Java服务器应用程序,我需要在服务器机器上打开哪个端口,以便客户端应用程序可以连接到它?

我想在服务器机器上设置防火墙,但我不知道该打开哪个端口。

9个回答

28

RMI通常不能通过防火墙工作,因为它使用不可预测的端口(它从1099开始,然后在此之后运行到随机端口)。

在这种情况下,通常需要使用HTTP隧道来传输RMI,这在这里有很好的描述。


8
时间已经使这个答案有些过时。如果你使用的是Java 7 update 4版本,则可以使用标志-Dcom.sun.management.jmxremote.rmi.port=7091来解决问题。请参考以下博客文章:http://hirt.se/blog/?p=289 - gm3dmo
@gian1200 这个链接本来就不应该被发布。HTTP隧道在官方RMI文档中已经有充分的描述,没有必要引用任意第三方参考资料。然而,这并不是解决这个问题所必需的:请看我的回答。 - user207421
1
@simgineer 注册表使用1099端口,激活守护程序使用1098端口,远程对象可以使用任何符合RMI端口共享规则的端口。默认情况下,它使用动态端口,但这很容易被覆盖,这使得这个答案和一些评论不正确。 - user207421
1
@davey 那个属性是针对 JMX 的,而不是整个 RMI。 - user207421
1
什么?我不相信这个。我已经使用静态rmi端口多年了,那是唯一接受连接的端口,其余端口都被UFW阻止。我从来没有遇到过问题。编辑:user207421的答案解释了为什么会这样。 - Cybermonk
显示剩余7条评论

27
到目前为止,所有答案都是不正确的。注册表通常使用端口1099,但您可以更改它。但这还不是故事的结束。远程对象也使用端口,并且不一定是1099。
如果在导出时没有指定端口,则RMI使用随机端口。因此解决方案是指定一个端口号。如果有防火墙,则需要打开该端口。
对于扩展UnicastRemoteObject的远程对象,请在其构造函数中调用 super(port) 并提供某个非零端口号。
对于未扩展UnicastRemoteObject的情况,请向 UnicastRemoteObject.exportObject() 提供非零端口号。
这有一些要注意的地方。
如果正在使用套接字工厂,则您的RMIServerSocketFactory必须具有合理的equals()实现,以使端口共享起作用,即不能仅依赖于通过==或Object.equals()的对象标识。
如果您没有提供服务器套接字工厂,或者提供了一个具有明智的equals()方法但没有两者都提供,则可以为所有远程对象使用相同的非零显式端口号,例如createRegistry(1099)后跟任意数量的super(1099)或exportObject(..., 1099)调用。

这很有道理。 - Cybermonk
我现在发现在Java 8中,上面第三个要点所述的“RMI将自动与后续导出的远程对象共享该端口,而无需指定端口号”似乎不再正确。我仍在调查此事,如有必要,将进一步报告。 - user207421
我进一步调查了这个问题,发现要么是Oracle出了问题,要么我错了20年。因此,回答已经做出相应修改。 - user207421
@greengold 嗯? 如果您正在端口1099上导出客户端回调,则需要在客户端的防火墙中打开该端口。 - user207421
1
@MinhNghĩa 注册表不使用随机端口,而远程对象的端口嵌入到与注册表绑定的存根中。TCP客户端不需要固定的端口号。 - user207421
显示剩余2条评论

9
在RMI中,涉及到端口有两个不同的机制:
  1. 默认情况下,RMI注册表使用1099端口。

  2. 客户端和服务器(存根、远程对象)通过随机端口通信,除非在导出远程对象时指定了固定端口。通信是通过使用0作为起始端口的套接字工厂启动的,这意味着使用1到65535之间的任何可用端口。


但我从某个地方听说有些Java应用程序连接被设置为使用随机端口。你知道这是什么类型的Java连接吗?这与Java RMI有关吗?谢谢。 - kwc
3
可以,但具体要看这个链接http://stackoverflow.com/questions/1706685/java-rmi-client-side-random-ports的详细信息。 - Kai Sternad
默认情况下,RMI Registry 使用1099端口。默认情况下,RMI远程对象使用随机系统分配的端口,除非在导出远程对象时指定了固定的端口。 - user207421
只有部分翻译了。你忽略了我评论中最后的十二个单词。 - user207421
@EJP:谢谢。我将您评论的最后一部分添加到答案中。 - Kai Sternad
在此过程中,您引入了另一个错误。端口范围为1-65535,而不是0-65535。 - user207421

3

通常使用rmiregistry命令在服务器上设置端口。您可以在命令行上设置端口,否则将默认为1099。


最好是将太阳页面的链接发送给您:http://java.sun.com/docs/books/tutorial/rmi/running.html如果是Linux系统,请确保您的路径中包含$JAVA_HOME/bin,这样您就可以运行该命令了。 - El Guapo
1
这仅适用于注册表。这还不是故事的结束。 - user207421

2
如果您可以修改客户端,则让其打印出远程引用,您就可以看到它正在使用哪个端口。例如:
ServerApi server = (ServerApi) registry.lookup(ServerApi.RMI_NAME);
System.out.println("Got server handle " + server);

将会产生类似以下的结果:

获得服务器句柄 Proxy[ServerApi,RemoteObjectInvocationHandler[UnicastRef [liveRef: [endpoint:172.17.3.190:9001,objID:[-7c63fea8:...

在这里您可以看到端口号为 9001。如果远程类没有指定端口,则它会在重启后更改。如果您想使用固定的端口,则需要确保远程类构造函数执行以下操作:

super(rmiPort)

0

取决于您如何实现RMI,您可以设置注册表端口(注册表是“服务的唯一点”)。如果您没有设置显式端口,则注册表将默认使用1099端口。在某些情况下,您可能会遇到防火墙问题,防火墙不允许您的rmi-client看到注册表后面的存根和对象,因为这些东西运行在随机端口上,与注册表使用的不同端口,并且该端口被防火墙阻止 - 当然了。 如果您使用RmiServiceExporter来配置您的RmiServer,则可以使用方法rmiServiceExporter.setServicePort(port)来固定rmi端口,并在防火墙中打开此端口。

编辑:我通过这篇文章解决了这个问题:http://www.mscharhag.com/java/java-rmi-things-to-remember


你引用的博客完全忽略了 UnicastRemoteObject.UnicastRemoteObject() 构造函数和 UnicastRemoteObject.exportObject() 中的 port 参数。RmiServiceExporter 是 Spring 的一部分,而不是 Java RMI。 - user207421
@EJP,我回答了这篇文章的核心问题,并补充说明了使用Spring更改服务端口的解决方案。正如你所看到的,我的话是以“如果您使用RmiServiceExporter…”开头的。感谢你的帮助性回复。 - Marco Blos
你回答了其中一个问题,并且介绍了Spring,而且没有在问题中提到它。 - user207421

-1

java.rmi.registry.Registryjavadoc

因此,注册表的远程对象实现通常使用众所周知的地址导出,例如使用众所周知的ObjID和TCP端口号(默认值为1099)。

请参阅java.rmi.registry.LocateRegistry的javadoc以获取更多信息。


这仅适用于注册表。这并不是故事的结局。 - user207421

-1

端口在这里可用:java.rmi.registry.Registry.REGISTRY_PORT(1099)


注册表默认端口在此处可用。但这还不是故事的结局。 - user207421

-1

参考其他答案,这是我的看法 -

客户端和服务器端都涉及到端口。

  • 对于服务器/远程端,如果您导出对象而不提供端口,则远程对象将使用随机端口进行侦听。

  • 当客户端查找远程对象时,它总是在其一侧使用随机端口,并将连接到上述列出的远程对象端口。


如果RMI托管在随机端口(比如50000)上,会有任何问题吗? - ArigatoManga
不,只要端口可用,您可以使用任何端口来托管注册表。 - Nrj
@ArigatoManga,“RMI在随机端口上托管”是没有意义的。您应该使用1099作为RMI注册表。这就是它的用途。 - user207421
@user207421 1099 是默认端口,但并不是唯一可用的端口。您可以覆盖它并仍然访问注册表。 - Nrj

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