Java 如何在一些自由端口上创建一个新的、唯一的RMI注册表? 处境

Java 如何在一些自由端口上创建一个新的、唯一的RMI注册表? 处境,java,jenkins-plugins,rmi,Java,Jenkins Plugins,Rmi,我正在编写一个Jenkins build step插件,希望本地主机上的其他进程调用插件的主进程函数并为其提供数据对象 为此,我决定使用RMI,因此我想创建一个RMI注册表,以便其他进程可以调用我的函数: 我希望注册表获取系统上的任何可用端口。通常,这是通过向注册表/套接字创建提供0端口来完成的 但是,RMI注册表维护一个ID,如果JVM上已经存在该ID的注册表,则会阻止后续创建。端口为0时,该注册表的ID为0 问题: 同一JVM实例(插件)上还有其他参与者,他们可能已经创建或希望在端口0上创

我正在编写一个Jenkins build step插件,希望本地主机上的其他进程调用插件的主进程函数并为其提供数据对象

为此,我决定使用RMI,因此我想创建一个RMI注册表,以便其他进程可以调用我的函数:

我希望注册表获取系统上的任何可用端口。通常,这是通过向注册表/套接字创建提供0端口来完成的

但是,RMI注册表维护一个ID,如果JVM上已经存在该ID的注册表,则会阻止后续创建。端口为0时,该注册表的ID为0

问题: 同一JVM实例(插件)上还有其他参与者,他们可能已经创建或希望在端口0上创建RMI注册表以进行端口发现。这会阻止我使用空闲端口创建自己的注册表。这是我的问题,因为我不想与这个JVM上的其他注册表冲突,但仍然可以获得一个可用的空闲端口

有什么解决办法吗

我做错什么了吗

我拒绝的东西
  • 如果使用现有注册表,我会担心绑定会与现有绑定冲突

  • 我试图为
    LocateRegistry.createRegistry
    提供一个自定义
    RMIServerSocketFactory
    实现,选择一个空闲端口(port=0),并使用id的任何其他端口调用
    createRegistry
    本身。然而,创建的注册表不知何故使用了正确的端口,但内部认为它使用了给定的端口。我担心,这将导致以后出现更多的问题。此外,我不能选择一个不存在的id,因为如果它们被证明已经被使用,我必须尝试几个。这与我开始解决的端口问题相同

  • 用套接字连接戳一个端口,然后在该端口上创建一个注册表对我来说不起作用。因为这在放弃端口和在该端口上创建注册表之间引入了一个间隙。我不希望另一个进程同时跳入并占用端口


总结我在这段时间里发现的情况,RMI并不适合我要介绍的场景

Java的RMI机制设计用于:

  • 在默认端口1099共享注册表
  • 在预先提供的特定端口共享注册表
在这两种情况下,这些问题都适用:

  • 如果端口已在使用中,则创建注册表失败,留下打开的操作
  • 重用您自己无法控制的RMI注册表可能会导致注册表在通信过程中停机(因为它的进程可能因任何有效原因停机)
  • 如果您的进程是短期的,那么“查看默认注册表是否存在,如果不创建它”是一种错误的模式。其他进程将绑定到您创建的注册表,然后该注册表将随进程一起关闭
  • 同一注册表上的所有服务器实例都需要使用一个绑定,希望不会发生冲突
  • 如果有多个类似的服务器/客户机进程使用相同的实现(例如并行作业),因此具有相同的绑定名称,则它们需要通过唯一的绑定名称对各自的通信进行排序
RMI机制不是为创建专用于单个服务器/客户端通信的即席RMI注册表而设计的:

  • 在随机空闲端口上创建RMI注册表(通过提供port=0)只在JVM进程中的第一次调用上起作用。在另一个随机空闲端口上创建另一个RMI注册表的任何进一步尝试都将失败
  • 在随机空闲端口上创建RMI注册表(通过自定义RMISocketFactory)会导致内部状态不一致。此外,您还需要预先确定要向注册表提供哪个ID,这首先会破坏使用RMI注册表的目的
  • 无法关闭RMI注册表。只要进程的JVM保持在线,它就保持在线

因此,在插件场景中,在同一JVM中,其他参与者可能会执行代码,您需要启动多个与非常相似的衍生进程的通信,并且可能有其他进程执行相同的操作,RMI会打开多个无法轻松缓解的故障点。

1。我总是使用远程接口的完整包/类名作为绑定名。这样的话,实际上就不存在名称冲突的可能性。您必须解释“然而,创建的注册表以某种方式使用了正确的端口,但内部认为它使用了给定的端口”的确切含义。3。但是在
RMISocketFactory
中指定
newserversocket(0)
会自动为您提供一个空闲端口。到那时,所有的猜测都结束了。然后,您所要做的就是查询它的本地端口,并将其存储在客户端可以找到它的地方,然后将该套接字返回给调用者。这就留下了如何与客户沟通的问题。@user207421。这是一个很好的推荐,谢谢!当现有RMI服务器位于不同的JVM上时,我们在向该服务器声明消息相关自定义定义(如返回类型)时也遇到问题。因此,我们没有朝那个方向前进。@user207421 2。创建的注册表将端口参数分为两种:一种是ID,另一种是某种类型的端口变量。但是,当我们选择一个不同的实际端口(通过我们自己的RMISocketFactory)时,创建的注册表实际上使用了这个不同的端口,但是在内部有一个给定参数port的缓存,作为ID和port变量。我无法理解其影响的前后矛盾。