简体   繁体   English

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

[英]Low-latency IPC between C++ and Java

What is the best way to implement C++/Java IPC for the following situation?对于以下情况,实现 C++/Java IPC 的最佳方法是什么?

(Someone recently asked a similar question , but my requirements are more specific) (最近有人问了类似的问题,但我的要求更具体)

  1. I have two programs -- one written in C++, the other in Java -- that need to communicate with each other.我有两个程序——一个用 C++ 编写,另一个用 Java 编写——它们需要相互通信。 Both are running on the same machine.两者都在同一台机器上运行。

  2. The programs send messages to each other.程序相互发送消息。 Messages are typically short (less than a few hundred bytes), but could potentially be 100KB or more in size.消息通常很短(少于几百字节),但可能有 100KB 或更大的大小。

  3. Messages do not need to be acknowledged (ie, not a request/response model like HTTP).消息不需要被确认(即,不是像 HTTP 那样的请求/响应 model)。 For example, the C++ program sends a message to the Java program, and the Java program may reply by sending a message to the C++ program at a later time -- and vice versa. For example, the C++ program sends a message to the Java program, and the Java program may reply by sending a message to the C++ program at a later time -- and vice versa.

  4. An ideal solution would have a) very low latency, b) no security hassles (user does not have to authorize ports to be opened etc.) and c) will be platform-agnostic.一个理想的解决方案将具有 a) 非常低的延迟,b) 没有安全问题(用户不必授权打开端口等)和 c) 将与平台无关。

My first thought was using sockets -- each program would act as a server to the other.我的第一个想法是使用sockets - 每个程序都将充当另一个程序的服务器。 Sockets have more overhead than other forms of IPC, and I don't know how the server would inform the client of the port number if I let the system auto-assign port numbers. Sockets 的开销比 IPC 的其他 forms 的开销更大,如果我让系统自动分配端口号,我不知道服务器如何通知客户端端口号。 I've also considered named pipes , but they are not supported (at least not consistently) across different platforms.我也考虑过命名管道,但它们在不同平台上不受支持(至少不一致)。 JNI looks like an option, but can it cross process boundaries? JNI看起来像一个选项,但它可以跨越进程边界吗?

Any suggestions?有什么建议么?

Thanks!谢谢!

FOLLOW-UP QUESTIONS后续问题

  1. If I go with sockets, would I need to open two sockets to allow for asynchronous communication as described above?如果我 go 和 sockets,我是否需要打开两个sockets 以允许如上所述的异步通信?

I'd suggest you to use TCP sockets .我建议您使用TCP sockets

The actual overhead of TCP sockets, as of my experience, is very very low compared to the other tasks' workload of the applications, at least the ones I use to develop.根据我的经验,TCP sockets 的实际开销与应用程序的其他任务的工作量相比非常非常低,至少是我用来开发的那些。 I mean, sometimes even if sockets' latency is twice as the latency of other IPC mechanisms, in the overall workflow they have very little impact.我的意思是,有时即使套接字的延迟是其他 IPC 机制的延迟的两倍,在整个工作流程中它们的影响也很小。 And it saves you the hassle of making IPC between a Java application and a C++ one, that will eventually require you to use a specific Java library that uses JNI, with the overhead of JNI and the one of the library itself.它为您省去了在 Java 应用程序和 C++ 应用程序之间进行 IPC 的麻烦,这最终将要求您使用特定的 ZD52387880E1EA22817A72D3759213819NIZ 库的开销和库本身的开销。

I've actually measured, in my Java applications, that Garbage Collector impact is far more important than the latency caused by " loopback " TCP sockets.我实际测量过,在我的 Java 应用程序中,垃圾收集器的影响远比“环回”TCP sockets 引起的延迟重要得多。

Moreover, TCP sockets are more scalable (and portable.) than traditional IPC?此外,TCP sockets 比传统的 IPC 更具可扩展性(和便携性。)? What if in the future you'll have to run the client and the server on different machines, In the 'TCP sockets' scenario, you'll have to do a 5-minute hack, in the 'traditional IPC' scenario.如果将来您必须在不同的机器上运行客户端和服务器,在“TCP 套接字”场景中,您将不得不在“传统 IPC”场景中进行 5 分钟的破解。 you'll have to rewrite the whole IPC stuff.你将不得不重写整个 IPC 的东西。

However, what is the general workflow of your application?但是,您的应用程序的一般工作流程是什么?

Even if the acknowledgement is not required, I'd suggest to use TCP (and not UDP) to avoid unsorted delivery (which leads to pain in the ass when it comes to rearrange the stuff you received - some of your messages are 100KB and this doesn't fit in a UDP packet).即使不需要确认,我也建议使用 TCP(而不是 UDP)来避免未排序的交付(这会导致在重新排列您收到的内容时感到头疼 - 您的一些消息是 100KB,而这不适合 UDP 数据包)。

In reply to your last question, for the server to inform the client about the port, you can just make the server launch the client with a specific 'port' command line parameter, or make the server save a small file under /tmp (or another temporary directory) with the port number written inside.在回答您的最后一个问题时,为了让服务器通知客户端有关端口,您可以让服务器使用特定的“端口”命令行参数启动客户端,或者让服务器在 /tmp 下保存一个小文件(或另一个临时目录),里面写着端口号。

I've heard good things about ZeroMQ for specifically these sort of scenarios.我听说过有关ZeroMQ的好消息,特别是针对这类场景。 It even boasts to be faster than TCP in some cases.在某些情况下,它甚至声称比 TCP 更快。 In short, certainly won't hurt to try it out.简而言之,尝试一下肯定不会有什么坏处。

An alternative is using memory mapped files and keeping it portable by checking compiler settings if you are posix or not.另一种方法是使用 memory 映射文件,并通过检查编译器设置是否为 posix 来保持它的可移植性。 POSIX OS's have mmap() and in windows you would use CreateFileMapping() POSIX 操作系统具有mmap()并且在 windows 中,您将使用CreateFileMapping()

In the boost library is a portable implementation for C++ and in java you should be able to use FileChannel() .在 boost 库中是 C++ 的可移植实现,在 java 中,您应该能够使用FileChannel()

This page does a good job of explaining how this can be used for IPC http://en.wikipedia.org/wiki/Memory-mapped_file该页面很好地解释了如何将其用于 IPC http://en.wikipedia.org/wiki/Memory-mapped_file

When you say very low latency, you need to qualify that.当您说非常低的延迟时,您需要对其进行限定。 You can send messages over a Socket loop back with a RTT of 20 microsecond.您可以通过 Socket 环回发送消息,RTT 为 20 微秒。 If this is fast enough, I would do that.如果这足够快,我会这样做。

If this is not fast enough I would just place the C++ inside the Java application and call it via JNI.如果这还不够快,我只需将 C++ 放在 Java 应用程序中并通过 JNI 调用它。 This would give you about 30 nano-second RTT.这将为您提供大约 30 纳秒的 RTT。

The problem with using memory mapped data is getting the interlocking right.使用 memory 映射数据的问题在于获得正确的互锁。 You might find a solution which works on one system, but might not work on others.您可能会找到适用于一个系统但可能不适用于其他系统的解决方案。

Using JNI would allow access to all of the possiblities in the system, not just those supported directly in Java;使用 JNI 将允许访问系统中的所有可能性,而不仅仅是 Java 中直接支持的那些; it would be necessary, for example, if you used shared memory.例如,如果您使用共享 memory,这将是必要的。 JNI is, itself, rather expensive, however.然而,JNI 本身相当昂贵。

The question of latency is tricky, because none of the mechanisms I know given any guarantees.延迟问题很棘手,因为我所知道的机制都没有提供任何保证。 All in all, the fastest would probably be some form of shared memory, using signals to wake up the other process when data is present.总而言之,最快的可能是某种形式的共享 memory,当数据存在时使用信号唤醒另一个进程。 This would require using JNI on the Java side, but done correctly, would probably still give the lowest latency—doing it correctly (ensuring that no messages get lost) can be far from trivial, however.这将需要在 Java 端使用 JNI,但如果做得正确,可能仍然会提供最低的延迟——但是,正确执行(确保没有消息丢失)绝非易事。 Unix based platforms do support queueing signals, and handling them as events in a separate thread;基于 Unix 的平台确实支持排队信号,并在单独的线程中将它们作为事件处理; I don't know about Windows.我不知道 Windows。

Other than that, a named pipe is generally pretty effective;除此之外,命名为 pipe 通常非常有效; the latency can be as good as shared memory, but it takes more time to get the data through (since it must be copied through the system).延迟可以与共享的 memory 一样好,但需要更多时间来获取数据(因为它必须通过系统复制)。 And it should be possible to access it directly from Java, without using JNI.并且应该可以直接从 Java 访问它,而无需使用 JNI。 Under Unix, it's also possible to configure sockets to respond just as quickly (in fact, this is what a named pipe is under the hood);在 Unix 下,还可以配置 sockets 以同样快速地响应(实际上,这就是名为 pipe 的引擎盖下的内容); I don't know if the Java interface supports these configuration options, however, and again, I don't know whether they're available under Windows.我不知道 Java 接口是否支持这些配置选项,但是,我不知道它们是否在 Windows 下可用。

An alternative would be to use an embedded DB (since you're considering multiple IPCs, I assume both the applications are on the same machine).另一种方法是使用嵌入式数据库(因为您正在考虑多个 IPC,我假设这两个应用程序都在同一台机器上)。

I use to work on an application earlier where the c++ application fetches data from all sorts of channels and put it in the DB (an in-memory database; TimesTen).我以前在一个应用程序上工作,其中 c++ 应用程序从各种渠道获取数据并将其放入数据库(内存数据库;TimesTen)。 In order to display that data to the user, the Java application would query it from the DB.为了向用户显示该数据,Java 应用程序将从数据库中查询它。

For your use, I don't know if you'd be willing to consider Oracle's Timesten, but you could as well use Berkeley's embedded DB.对于您的使用,我不知道您是否愿意考虑 Oracle 的 Timesten,但您也可以使用 Berkeley 的嵌入式数据库。

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

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