如何让两个JVM相互通信

81
我有如下情况:
我有2个JVM进程(实际上是2个独立运行的Java进程,而不是2个线程)在本地机器上运行。我们称它们为ProcessA和ProcessB。
我想让它们相互通信(交换数据),例如ProcessA向ProcessB发送消息以执行某些操作。
现在,我通过编写临时文件并使这些进程定期扫描此文件来解决此问题。我认为这种解决方案不太好。
有什么更好的替代方案来实现我的目标吗?

与此同时,内存映射文件已被添加到可能的方法中。 - Curiosa Globunznik
7个回答

92

多个选项可用于 IPC

基于套接字(裸骨)的网络

  • 不一定困难,但:
    • 可能会过于冗长,没有太大帮助,
    • 在编写更多代码时可能会提供更多的错误表面。
  • 您可以依赖现有的框架,如Netty

RMI

  • 从技术上讲,这也是网络通信,但对您来说是透明的。

完整的消息传递体系结构

  • 通常也是基于RMI或网络通信构建的,但支持复杂的对话和工作流程
  • 对于简单的事情可能过于重量级
  • ActiveMQJBoss Messaging等框架

Java管理扩展(JMX)

  • 更多用于JVM管理和监控,但如果您主要想让一个进程查询另一个进程的数据或向其发送某个请求以执行操作(如果它们不太复杂),则可以帮助实现所需。
  • 还可以通过RMI(或其他可能的协议)工作
  • 一开始可能有些难以理解,但实际上非常容易使用。点此查看详细教程。
  • 文件共享/文件锁定

    • 这就是你现在正在做的事情。
    • 虽然可行,但涉及到许多需要处理的问题。

    信号

    • 你可以简单地向其他项目发送信号。
    • 但它相当有限并且需要实现一个翻译层(这是可行的,但更像是一个玩具而不是严肃的东西)。

    如果没有更多细节,那么基于网络的IPC方法似乎是最好的选择,因为它:

    • 最具可扩展性(可以添加新功能和工作流程)
    • 最轻量级(对应用程序的内存占用最小)
    • 最简单(设计上最简单)
    • 最教育人(学习如何实现IPC)(正如您在评论中提到“套接字很难”,其实它并不难,并且应该是您要解决的问题之一)

    话虽如此,基于您的示例(仅请求其他进程执行操作),JMX也可能足够满足您的需求。


    请记住,当处理多个类加载器时,JMX存在问题,因为对象在JVM中是共享的。强制转换存在问题。有时可能需要进行序列化/反序列化。 - LppEdd

    23

    我在Github上添加了一个名为Mappedbus(http://github.com/caplogic/mappedbus)的库,它可以使两个或多个Java进程/JVM通过交换消息进行通信。该库使用内存映射文件,并利用fetch-and-add和volatile读/写来同步不同的读者和写者。我使用该库测量了两个进程之间的吞吐量,可达每秒4000万条消息,平均延迟为25纳秒,用于读/写单个消息。


    5
    如果我没记错的话,这个库将一些固定大小的文件映射到内存,并追加消息直到文件末尾,那么当文件中全部内容被读取时,它是否会简单地停止运行?据我所知,它不是一个环形缓冲区。 - vach

    7
    你需要的是“进程间通信”。Java提供了一个简单的IPC框架,即Java RMI API。还有其他一些进程间通信机制,如管道、套接字、消息队列(这些都是概念,所以有实现这些机制的框架)。
    我认为在你的情况下,Java RMI或一个简单的自定义套接字实现就足够了。

    1
    就像使用管道(命名管道)一样。这是最简单的方法,因为您只需读取/写入普通文件即可。 - Dmitry Trifonov
    @DmitryTrifonov 管道只适用于在同一JVM中运行的两个线程,这个问题是针对2个不同进程的。 - Ignace Vau
    @IgnaceVau,你能详细讲解一下管道吗?我想了解更多(例如,示例,文档)。谢谢! - LppEdd

    3

    使用DataInput(Output)Stream的套接字,可以来回发送java对象。这比使用磁盘文件更容易,也比Netty更容易。


    2

    我倾向于使用jGroup在进程之间形成本地集群。它适用于在同一台计算机上的节点(也称为进程),在同一个JVM内,甚至跨越不同的服务器。

    一旦您了解基础知识,就很容易使用它,并且有选项可以在同一个JVM中运行两个或多个进程,这使得轻松测试这些进程变得容易。

    如果两者都在同一台机器上,则开销和延迟非常小(通常只有每个操作大约 >100ns 的TCP往返)。


    1

    我认为socket可能是更好的选择。


    Socket 实现起来比较困难,所以我认为这不是一种简单的方式,是否有其他解决方案?例如更高级别的 API、框架或者更容易实现的方法。 - tnk_peka
    1
    难度或简单取决于目的。对于简单的事情,我不相信使用重型库比简单地创建自己的Socket类更值得。 - M-D

    0

    早在2004年,我就实现了使用套接字完成任务的代码。从那时起,我多次寻找更好的解决方案,因为套接字方法会触发防火墙,让我的客户感到担忧。直到现在,还没有更好的解决方案。客户必须将数据序列化、发送,服务器必须接收并反序列化。这很容易。


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