C ++和Java之间的低延迟IPC

在以下情况下,实现C ++ / Java IPC的最佳方法是什么?

(有人最近问了一个类似的问题 ,但我的要求更具体)

  1. 我有两个程序 – 一个用C ++编写,另一个用Java编写 – 需要相互通信。 两者都在同一台机器上运行。

  2. 程序相互发送消息。 消息通常很短(少于几百字节),但可能大小为100KB或更多。

  3. 消息不需要被确认(即,不是像HTTP那样的请求/响应模型)。 例如,C ++程序向Java程序发送消息,Java程序可以通过稍后向C ++程序发送消息来进行回复 – 反之亦然。

  4. 一个理想的解决方案是:a)非常低的延迟,b)没有安全麻烦(用户不必授权打开端口等)和c)将是平台无关的。

我的第一个想法是使用套接字 – 每个程序都充当另一个程序的服务器。 套接字比其他forms的IPC有更多的开销,我不知道如果让系统自动分配端口号,服务器将如何通知客户端端口号。 我也考虑过命名管道 ,但它们在不同平台上不受支持(至少不一致)。 JNI看起来像一个选项,但它可以跨越流程边界吗?

有什么建议么?

谢谢!

后续问题

  1. 如果我使用套接字,我是否需要打开两个套接字以允许异步通信,如上所述?

我建议你使用TCP套接字

根据我的经验,TCP套接字的实际开销与其他任务的应用程序工作负载相比非常低,至少是我用来开发的。 我的意思是,有时即使套接字的延迟是其他IPC机制的延迟的两倍,在整个工作流程中它们的影响也很小。 它为您节省了在Java应用程序和C ++之间进行IPC的麻烦,最终需要您使用使用JNI的特定Java库,以及JNI和库本身的开销。

在我的Java应用程序中,我实际上已经测量过,垃圾收集器的影响比“ 环回 ”TCP套接字引起的延迟要重要得多。

此外,TCP套接字比传统IPC更具可扩展性(并且可移植!)。 如果将来你必须在不同的机器上运行客户端和服务器怎么办? 在“TCP套接字”场景中,你将不得不做5分钟的黑客攻击,在“传统的IPC”场景中,你将不得不重写整个IPC的东西。

但是,您的应用程序的一般工作流程是什么?

即使不需要确认,我建议使用TCP(而不是UDP)来避免未经分类的传送(当重新排列收到的内容时会导致痛苦 – 你的一些消息是100KB,这个不适合UDP数据包)。

在回答您的上一个问题时,为了让服务器通知客户端端口,您可以让服务器使用特定的“端口”命令行参数启动客户端,或者让服务器在/ tmp下保存一个小文件(或者另一个临时目录),里面写有端口号。

我已经听说ZeroMQ特别针对这些场景。 在某些情况下,它甚至比TCP更快。 总之,试一试肯定不会受到伤害。

另一种方法是使用内存映射文件并通过检查编译器设置保持可移植性(如果您是posix或不是posix)。 POSIX OS有mmap() ,在windows中你会使用CreateFileMapping()

在boost库中是C ++的可移植实现,在java中你应该能够使用FileChannel()

这个页面很好地解释了如何将它用于IPC http://en.wikipedia.org/wiki/Memory-mapped_file

当你说延迟非常低时,你需要有资格。 您可以通过Socket循环发送消息,RTT为20微秒。 如果这足够快,我会这样做。

如果这还不够快,我只需将C ++放在Java应用程序中并通过JNI调用它。 这将为您提供大约30纳秒的RTT。

使用内存映射数据的问题是获得联锁权。 您可能会找到适用于一个系统的解决方案,但可能无法在其他系统上运行。

使用JNI将允许访问系统中的所有可能性,而不仅仅是Java中直接支持的那些可能性; 例如,如果你使用共享内存,那将是必要的。 然而,JNI本身相当昂贵。

延迟问题很棘手,因为我所知道的机制都没有给出任何保证。 总而言之,最快的可能是某种forms的共享内存,使用信号在数据存在时唤醒其他进程。 这需要在Java端使用JNI,但是如果正确完成,可能仍会提供最低延迟 – 正确地执行它(确保没有消息丢失)可能远非微不足道。 基于Unix的平台确实支持排队信号,并在单独的线程中将它们作为事件处理; 关于Windows,我不知道。

除此之外,命名管道通常非常有效; 延迟可以和共享内存一样好,但是需要更多时间来获取数据(因为它必须通过系统复制)。 并且应该可以直接从Java访问它,而不使用JNI。 在Unix下,也可以配置套接字以便快速响应(实际上,这就是命名管道的底层); 我不知道Java接口是否支持这些配置选项,但是,我不知道它们是否在Windows下可用。

另一种方法是使用嵌入式数据库(因为您正在考虑多个IPC,我假设两个应用程序都在同一台机器上)。

我之前使用的是c ++应用程序从各种通道中获取数据并将其放入DB(内存数据库; TimesTen)中的应用程序。 为了向用户显示该数据,Java应用程序将从DB查询它。

对于您的使用,我不知道您是否愿意考虑Oracle的Timesten,但您也可以使用Berkeley的嵌入式数据库。