7

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

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

似乎更安全的解决方案可能是使用 JNI 和命名管道 API (\.\pipe\blah),使连接双方的平台特定混乱不堪。

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

4

11 回答 11

7

你应该看看Google 的Protocol Buffers,它支持 C++ 和 Java。

于 2008-11-05T23:12:48.727 回答
5

命名管道会比 TCP 更有效,但是只使用共享内存块怎么样?

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

于 2008-11-05T22:16:26.173 回答
4

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

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

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

于 2008-11-05T22:18:50.020 回答
2

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

下一个替代方法是使用两个进程的标准输入/标准输出。如果一个可以执行另一个,这可能会非常快。

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

于 2009-09-18T04:57:25.980 回答
1

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

看看这个:通过 jni 接口共享输出流

文章中的片段,它将数据从 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 工具)、UDP 或 TCP

于 2010-08-24T14:01:03.323 回答
1

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

于 2008-11-07T10:56:20.850 回答
0

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

于 2008-11-05T22:59:52.357 回答
0

使用 System.out 和 System.in 怎么样?

如果这不合适,那么 Sockets 是您最好的选择。

于 2008-11-05T23:04:48.570 回答
0

如果您的 C++ 进程启动 Java 进程,它可能会受益于继承的Channel 。此外,如果 Java 进程正在使用文件,我建议探索transferTotransferFrom方法。在进行文件到文件 IO 时,这些避免了用户和内核空间之间不必要的来回切换;如果您使用特殊的套接字通道,可能会启动相同的优化。

于 2008-11-05T23:23:38.563 回答
0

我推荐一个 UDP“连接”,它确认接收到的每 N 个数据包都没有错误,并请求重新传输它将丢失的几个数据包。

于 2008-11-06T01:24:51.703 回答
-2

我建议不要使用 JNI,因为它很难调试。如果 C++ 代码出现段错误或抛出未捕获的异常,您的 JVM 将崩溃,您将不知道原因。

于 2008-11-05T22:30:22.260 回答