简体   繁体   English

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

[英]How to create a new, unique RMI registry on some free port?

Situation情况

I'm writing a Jenkins build step plugin, and want my other processes on localhost to call my plugin's main process' functions and give it data objects.我正在编写一个 Jenkins 构建步骤插件,并希望本地主机上的其他进程调用我的插件的主进程函数并为其提供数据对象。

For this, I decided to use RMI, therefore I want to create an RMI registry, so the other processes can call my functions:为此,我决定使用 RMI,因此我想创建一个 RMI 注册表,以便其他进程可以调用我的函数:

https://docs.oracle.com/javase/7/docs/api/java/rmi/registry/LocateRegistry.html https://docs.oracle.com/javase/7/docs/api/java/rmi/registry/LocateRegistry.html

I want the registry to take any free port available on the system.我希望注册表采用系统上可用的任何空闲端口。 Usually this is done by providing a port of 0 to the registry/socket creation.通常这是通过为注册表/套接字创建提供端口 0 来完成的。

However, an RMI registry maintains an ID, preventing a subsequent creation if a registry of that ID already exists on the JVM.但是,RMI 注册表维护一个 ID,如果 JVM 上已经存在该 ID 的注册表,则阻止后续创建。 With a port of 0, that registry's ID is 0.如果端口为 0,则该注册表的 ID 为 0。

Question问题

There are other actors on the same JVM instance (plugins), that may have created or may want to create a RMI registry on port 0 for port discovery.在同一 JVM 实例(插件)上还有其他参与者,他们可能已经创建或可能希望在端口 0 上创建 RMI 注册表以进行端口发现。 This prevents me from creating my own registry with a free port.这使我无法使用空闲端口创建自己的注册表。 This is my problem, because I don't want to collide with other registries on this JVM, yet still get an available free port.这是我的问题,因为我不想与此 JVM 上的其他注册表发生冲突,但仍然可以获得可用的免费端口。

Is there some solution for this?有什么解决办法吗?

Did I get something wrong?我是不是搞错了什么?

Things I rejected我拒绝的东西

  • If I used an existing registry, I'd be concerned that my bindings will collide with existing bindings.如果我使用现有的注册表,我会担心我的绑定会与现有的绑定发生冲突。

  • I tried to provide a custom RMIServerSocketFactory implementation to LocateRegistry.createRegistry , choosing a free port (port = 0), and calling createRegistry itself with any other port for id.我尝试为LocateRegistry.createRegistry提供自定义RMIServerSocketFactory实现,选择一个空闲端口(端口 = 0),并使用任何其他端口调用createRegistry本身作为 id。 However, the created Registry somehow uses the correct port, but internally thinks it uses the given port.但是,创建的注册表以某种方式使用了正确的端口,但内部认为它使用给定的端口。 I am concerned, this will lead to further problems later on.我担心,这会导致以后出现更多问题。 Also, I cannot reliable choose a nonexisting id, as I'd have to try several if they turn out to be used already.另外,我不能可靠地选择一个不存在的 id,因为如果它们已经被使用,我必须尝试几个。 This is the same problem I set out to solve with the ports.这与我打算用端口解决的问题相同。

  • Poking a port with a socket connection, then creating a Registry on that port does not work for me.用套接字连接戳一个端口,然后在该端口上创建一个注册表对我不起作用。 Because this introduces a gap between forfeiting the port and creating the registry on that port.因为这在没收端口和在该端口上创建注册表之间引入了差距。 And I don't want another process to jump in and take the port in the mean time.而且我不希望另一个进程同时加入并占用该端口。

Summarizing what I found out in the mean time, RMI is not a good fit for the scenario I want to cover.总结一下我同时发现的情况,RMI 并不适合我想要涵盖的场景。

Java's RMI mechanism is designed for: Java 的 RMI 机制设计用于:

  • sharing a Registry at the default port of 1099在默认端口 1099 共享注册表
  • sharing a Registry at a specific port that you provide beforehand在您预先提供的特定端口共享注册表

In both cases these problems apply:在这两种情况下,这些问题都适用:

  • If the port is already in use then creating the Registry fails, leaving open what to do about it.如果端口已在使用中,则创建注册表将失败,并保持打开状态。
  • Reusing an RMI registry that you do not control yourself brings about the possibility that the registry goes down mid-communication (because its process can go down for any valid reason).重用您自己无法控制的 RMI 注册表会导致注册表在通信过程中出现故障(因为它的进程可能会因任何正当理由而停止 go)。
  • "Look if the default Registry exists, if not create it" is a bad pattern, if your process is short-lived.如果您的过程是短暂的,那么“查看默认注册表是否存在,如果不创建它”是一个不好的模式。 Other processes will bind to your created Registry, which then goes down with the process.其他进程将绑定到您创建的注册表,然后随着该进程关闭。
  • All server instances on the same Registry need to use a binding that hopefully does not collide.同一个 Registry 上的所有服务器实例都需要使用一个希望不会发生冲突的绑定。
  • If there are several similar server/client processes that use the same implementation (for example parallel jobs), and therefore the same binding names, they need to sort out their individual communication through unique binding names.如果有几个相似的服务器/客户端进程使用相同的实现(例如并行作业),因此有相同的绑定名称,它们需要通过唯一的绑定名称来整理它们各自的通信。

The RMI mechanism is not designed for creating an ad-hoc RMI registry that is dedicated to a single server/client communication: RMI 机制不是为创建专用于单个服务器/客户端通信的 ad-hoc RMI 注册表而设计的:

  • Creating an RMI registry on a random free port (by providing port=0) works only on the very first call within this JVM process.在随机空闲端口(通过提供端口=0)上创建 RMI 注册表仅适用于此 JVM 进程中的第一次调用。 Any further attempts at creating another RMI registry on another random free port fails.在另一个随机空闲端口上创建另一个 RMI 注册表的任何进一步尝试都会失败。
  • Creating an RMI registry on a random free port (by custom RMISocketFactory) leads to inconsistent internal state.在随机空闲端口(通过自定义 RMISocketFactory)上创建 RMI 注册表会导致内部 state 不一致。 Also, you need to sort out which ID to give the Registry up front, which defeats the purpose of using an RMI registry in the first place.此外,您需要预先确定要为注册表提供哪个 ID,这首先违背了使用 RMI 注册表的目的。
  • An RMI registry cannot be closed.无法关闭 RMI 注册表。 It stays online as long as the process's JVM stays.只要进程的 JVM 保持不变,它就会保持在线。

Therefore, in a plugin scenario, where, within the same JVM, other actors may execute code, and you need to start several communications to very similar spawned processes, and there may be other processes around, that do the same thing, RMI opens several points of failure that cannot easily be mitigated.因此,在插件场景中,在同一个 JVM 中,其他参与者可能会执行代码,并且您需要启动几个与非常相似的衍生进程的通信,并且周围可能有其他进程做同样的事情,RMI 会打开几个无法轻易缓解的故障点。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM