在Windows上从Java到C ++的高效数据传输

时间:2008-11-05 22:08:51

标签: java c++ pipe fifo

我希望将大量数据(最高~1 Gbit)从Java流式传输到C ++应用程序(两者都在同一台机器上)。我目前在Linux上使用FIFO,但也需要Windows解决方案。

最跨平台的方法似乎是本地套接字,但是: a)我不会从TCP校验和复制到&来自内核空间,和 b)普通用户的防火墙不会尝试检查并阻止连接吗?

似乎更安全的解决方案可能是使用JNI和命名管道API(\。\ pipe \ blah),在连接的两端产生令人难以置信的特定于平台的混乱。

这些真的是我的2个最佳选择(人们会推荐哪些?) 谢谢!

11 个答案:

答案 0 :(得分:7)

您应该查看Google支持C ++和Java的Protocol Buffers

答案 1 :(得分:4)

命名管道比TCP更有效,但是如何使用共享内存块?

我不知道Java端存在哪些原语用于与共享内存接口,但是从C ++端访问共享内存中的数据比从套接字或命名管道中读取数据更有效。您必须实现自己的流控制和阻塞原语,但这些可能非常简单。

答案 2 :(得分:4)

我会使用本地套接字,正如您所说,这是最跨平台的方法。

内核 - 用户空间副本不应该是一个问题,因为除了可能共享内存之外,您可以选择的任何其他方法都需要这种副本。它可以在每个Unix系统上使用,Windows也可以使用doing it

要在Java中使用共享内存,唯一的方法是通过您自己的.DLL / .SO和JNI来实现它。

答案 3 :(得分:2)

您最快的解决方案是内存映射共享内存段,并实现环形缓冲区或其他消息传递机制。在C ++中,这是直截了当的,而在Java中,您可以使用FileChannel.ma p方法使其成为可能。

下一个选择是使用两个进程的stdin / stdout。如果一个人可以执行另一个,这可能会非常快。

最后,正如您所说,您可以执行套接字IO。对于流视频,这不是一个很好的选择,但如果你传递XML,与其他处理相比,开销将是最小的。

答案 4 :(得分:1)

如果您对编写JNI感到满意,请考虑Boost.Interprocess。这将为您提供Linux和Windows上的可移植共享内存。请记住,没有用于读/写共享内存的内核往返。

答案 5 :(得分:1)

如果在“一个”函数调用中它是一大块数据,我会推荐JNI。

看看这个:Sharing output streams through a jni interface

文章中的片段,它将数据从c ++传输到java,反之亦然:

总之,从C与Java共享二进制数据(A / V文件,图像等)的一般策略需要字节数组。您可以在C中创建一个Java字节数组:

const char[] rawData = {0,1,2,3,4,5,6,7,8,9}; //Or get some raw data from somewhere
int dataSize = sizeof(rawData);
printf("Building raw data array copy\n");
jbyteArray rawDataCopy = env->NewByteArray(dataSize);
env->SetByteArrayRegion(rawDataCopy, 0, dataSize, rawData);

并将其传递给Java:

printf("Finding callback method\n");
//Assumes obj is the Java instance that will receive the raw data via callback
jmethodID aMethodId = env->GetMethodID(env->GetObjectClass(obj),"handleData","([B)V");
if(0==aMethodId) throw MyRuntimeException("Method not found error");
printf("Invoking the callback\n");
env->CallVoidMethod(obj,aMethodId, &rawDataCopy);

你会有一个看起来像这样的Java对象:

public class MyDataHandler {
  OutputStream dataStream;
  public MyDataHandler(OutputStream writeTo) { dataStream = writeTo;}
  public void handleData(byte[] incomingData) { dataStream.write(incomingData); }
}

该处理程序将通过本机方法传递给C,如:

public class NativeIntegration {
  public native void generateBinaryWithHandler(MyDataHandler handler);

  //Here we assume response is something like a network stream
  public void doCallNativeFunction(ResponseStream response) {
    MyDataHandler handler = new MyDataHandler(response);
    generateBinaryWithHandler(handler);
  }
}

此外,您还可以使用其他技术: CORBA,ASN.1(ASN.1 tool),UDP或TCP

答案 6 :(得分:0)

如果TCP的比特率太高,我会使用带有否定确认UDP的本地套接字(尽管我会首先尝试TCP并确认它是一个问题)。如果你在同一台机器上进行流式传输,那么丢弃的数据包应该是最小的(如果有的话),但添加一个否定确认层将为你处理这种情况。

答案 7 :(得分:0)

如何使用System.out和System.in?

如果这不合适,那么套接字是你最好的选择。

答案 8 :(得分:0)

如果您的C ++进程启动了Java进程,它可能会从inheritedChannel中受益。此外,如果Java进程正在使用文件,我建议您探索transferTotransferFrom方法。在执行文件到文件IO时,这些可以避免在用户和内核空间之间来回不必要地跳闸;如果你使用特殊的套接字通道,可能会有同样的优化。

答案 9 :(得分:0)

我建议使用UDP“连接”来确认每个没有故障的第N个数据包,并请求重传它将丢失的少数数据包。

答案 10 :(得分:-2)

我会建议反对JNI,因为它很难调试。如果C ++代码段错误或抛出未捕获的异常,您的JVM将崩溃,您将不知道为什么。