简体   繁体   English

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

[英]Efficient data transfer from Java to C++ on windows

I'm looking to stream lots of data (up to ~1 Gbit) from Java to a C++ application (both on the same machine). 我希望将大量数据(最高~1 Gbit)从Java流式传输到C ++应用程序(两者都在同一台机器上)。 I'm currently using a FIFO on Linux but need a Windows solution too. 我目前在Linux上使用FIFO,但也需要Windows解决方案。

The most cross-platform method seems to be a local socket, but: a) won't I get huge overhead from TCP checksumming and copying to & from kernel space, and b) won't the average user's firewall try to inspect the and maybe block the connection? 最跨平台的方法似乎是一个本地套接字,但是:a)我不会从TCP校验和从内核空间复制和从内核空间复制中获得巨大的开销,并且b)普通用户的防火墙不会尝试检查和也许阻止连接?

It seems like a safer solution may be to use JNI and the Named Pipe API (\\.\\pipe\\blah), making a god-awful platform-specific mess of both sides of the connection. 似乎更安全的解决方案可能是使用JNI和命名管道API(\\。\\ pipe \\ blah),这使得连接两端的平台特定混乱。

Are these really my 2 best options (and which would people recommend?) Thanks! 这些真的是我最好的两个选择(人们会推荐哪些?)谢谢!

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

Named pipes would be more efficient than TCP, but how about just using shared memory blocks? 命名管道比TCP更有效,但是如何使用共享内存块呢?

I don't know what primitives exist on the Java side for interfacing with shared memory, but from the C++ side it would be more efficient to access data in shared memory than read it out of either a socket or named pipe. 我不知道Java端存在什么原语用于与共享内存接口,但是从C ++方面来说,访问共享内存中的数据比从套接字或命名管道中读取数据更有效。 You would have to implement your own flow control and blocking primitives, but these could be fairly straight forward. 您必须实现自己的流控制和阻塞原语,但这些可能非常简单。

I would use a local socket, which is, as you state, the most cross-platform method. 我会使用本地套接字,正如您所说,这是最跨平台的方法。

Kernel-User space copies should not be an issue since any other method you could choose would requiere this kind of copy except for maybe shared memory. 内核用户空间副本不应该是一个问题,因为除了可能共享内存之外,您可以选择的任何其他方法都需要这种副本。 It is available on every Unix system and also Windows has its way of doing it 它可以在每个Unix系统上使用,Windows也可以使用

To use shared memory in Java the only way is to implement it by means of your own .DLL/.SO and JNI to access it. 要在Java中使用共享内存,唯一的方法是通过您自己的.DLL / .SO和JNI来实现它。

Your fastest solution will be memory mapping a shared segment of memory, and them implementing a ring-buffer or other message passing mechanism. 您最快的解决方案是内存映射共享内存段,并实现环形缓冲区或其他消息传递机制。 In C++ this is straight forward, and in Java you have the FileChannel.ma p method which makes it possible. 在C ++中,这是直截了当的,在Java中,你有FileChannel.ma p方法,这使它成为可能。

The next alternative would be to use the stdin/stdout of the two processes. 下一个选择是使用两个进程的stdin / stdout。 If one can exec the other, this can be quite fast. 如果一个人可以执行另一个,这可能会非常快。

Lastly, as you've noted, you can do socket IO. 最后,正如您所指出的,您可以执行套接字IO。 For streaming video this isn't a great option, but if your passing XML around, the overhead will be minimal in comparison to the other processing. 对于流视频,这不是一个很好的选择,但如果你传递XML,与其他处理相比,开销将是最小的。

If you're happy with writing JNI, consider Boost.Interprocess . 如果您对编写JNI感到满意,请考虑Boost.Interprocess This will give you portable shared memory on both Linux and Windows. 这将为您提供Linux和Windows上的可移植共享内存。 Remember that there's no kernel roundtrip for reading/writing shared memory. 请记住,没有用于读/写共享内存的内核往返。

If it's a big chunk of data in "one" function call I would recommend JNI. 如果在“一个”函数调用中它是一大块数据,我会推荐JNI。

Take a look at this: Sharing output streams through a jni interface 看看这个: 通过jni接口共享输出流

Snippet from the article, it transfert data from c++ to java, the opposite would be also easy to do: 从文章的片段,它将数据从c ++传输到java,相反也很容易做到:

In all, the general strategy for sharing binary data (A/V files, images, etc.) from C with Java requires byte arrays. 总之,从C与Java共享二进制数据(A / V文件,图像等)的一般策略需要字节数组。 You create a Java byte array in C like this: 您在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);

And pass it to Java like this: 并将它传递给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);

you would have a Java object that looked something like this: 你会有一个看起来像这样的Java对象:

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

That handler would be passed to C via native method like so: 该处理程序将通过本机方法传递给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);
  }
}

Also, you can use other technologies: CORBA, ASN.1 ( ASN.1 tool ), UDP or TCP 此外,您还可以使用其他技术:CORBA,ASN.1( ASN.1工具 ),UDP或TCP

I would use a local socket with negative acknowledgment UDP if the bit rate is going to be too high for TCP (although I would try TCP first and confirm that it is a problem). 如果TCP的比特率太高,我会使用带有否定确认UDP的本地套接字(尽管我会首先尝试TCP并确认它是一个问题)。 There should be minimal, if any, packets dropped if you are doing the streaming on the same machine, but the addition of a negative acknowledgement layer will take care of that case for you. 如果您在同一台计算机上进行流式处理,则应该删除最少的数据包(如果有的话),但添加否定确认层将为您处理这种情况。

How about using System.out and System.in? 如何使用System.out和System.in?

If that isn't suitable, then Sockets is your best bet. 如果那不合适,那么套接字是你最好的选择。

If your C++ process starts the Java process, it might benefit from the inheritedChannel . 如果您的C ++进程启动了Java进程,那么它可能会从inheritedChannel中受益。 Also, if the Java process is using a file, I recommend exploration of the transferTo and transferFrom methods. 此外,如果Java进程正在使用文件,我建议探索transferTotransferFrom方法。 When doing file to file IO, these avoid needlessly tripping back and forth between user and kernel space; 在执行文件到文件IO时,这些可以避免在用户和内核空间之间来回不必要地跳闸; the same optimizations might kick in if you're using a special socket channel. 如果您使用特殊的套接字通道,可能会启动相同的优化。

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

I would advise against JNI, because it is very difficult to debug. 我会建议反对JNI,因为它很难调试。 If the C++ code segfaults or throws an uncaught exception, your JVM will crash, and you will have no idea why. 如果C ++代码段错误或抛出未捕获的异常,您的JVM将崩溃,您将不知道为什么。

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

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