Эффективная передача данных с Java на C ++ в windows

Я ищу потоковую передачу большого количества данных (до ~ 1 Гбит) с Java в приложение C ++ (оба на одном компьютере). В настоящее время я использую FIFO в Linux, но мне также нужно решение для Windows.

Наиболее кроссплатформенным методом кажется локальный сокет, но: а) я не получу огромных накладных расходов из-за контрольных сумм TCP и копирования в и из пространства ядра, и б) не будет ли брандмауэр среднего пользователя пытаться проверить и может заблокировать соединение?

Похоже, что более безопасным решением может быть использование JNI и API именованных каналов (\. \ Pipe \ blah), что создаст ужасный беспорядок, зависящий от платформы, на обеих сторонах соединения.

Это действительно 2 моих лучших варианта (и какие люди рекомендуют?) Спасибо!


person Community    schedule 05.11.2008    source источник


Ответы (11)


Вам следует взглянуть на Protocol Buffers от Google, который поддерживает как C ++, так и Ява.

person John Channing    schedule 05.11.2008
comment
Protobuff определяет, ЧТО вы передаете, а не КАК. Вопрос здесь о КАК. - person Bruce; 23.05.2012
comment
Protobuff имеет свои собственные накладные расходы на ваши данные без какого-либо решения о том, КАК эффективно передавать (как упоминал @Bruce). Используйте разделяемую память. - person masoud; 08.01.2013

Именованные каналы будут более эффективными, чем TCP, но как насчет использования блоков общей памяти?

Я не знаю, какие примитивы существуют на стороне Java для взаимодействия с разделяемой памятью, но со стороны C ++ было бы более эффективно обращаться к данным в разделяемой памяти, чем читать их из сокета или именованного канала. Вам придется реализовать свои собственные примитивы управления потоком и блокировки, но это может быть довольно просто.

person Rob Walker    schedule 05.11.2008

Я бы использовал локальный сокет, который, как вы утверждаете, является наиболее кроссплатформенным методом.

Копии пространства ядра и пользователя не должны быть проблемой, поскольку любой другой метод, который вы можете выбрать, потребует такого типа копии, за исключением, возможно, общей памяти. Он доступен в каждой системе Unix, а также в Windows есть свой способ делаю это

Единственный способ использовать разделяемую память в Java - реализовать ее с помощью ваших собственных .DLL / .SO и JNI для доступа к ней.

person Fernando Miguélez    schedule 05.11.2008

Самым быстрым решением будет отображение памяти в общем сегменте памяти и реализация кольцевого буфера или другого механизма передачи сообщений. В C ++ это просто, а в Java у вас есть FileChannel.ma p метод, который делает это возможным.

Следующей альтернативой было бы использование stdin / stdout двух процессов. Если один может выполнить другой, это может быть довольно быстро.

Наконец, как вы заметили, вы можете выполнять ввод-вывод сокетов. Для потокового видео это не лучший вариант, но если вы передаете XML, накладные расходы будут минимальными по сравнению с другой обработкой.

person brianegge    schedule 18.09.2009


Если это большой кусок данных в «одном» вызове функции, я бы порекомендовал JNI.

Взгляните на это: Совместное использование потоки вывода через интерфейс jni

Фрагмент из статьи, он переносит данные из c ++ в java, обратное тоже было бы несложно:

В общем, общая стратегия совместного использования двоичных данных (аудио / видео файлов, изображений и т. Д.) Из C с Java требует массивов байтов. Вы создаете массив байтов Java в C следующим образом:

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

person Vincent    schedule 24.08.2010

Я бы использовал локальный сокет с UDP с отрицательным подтверждением, если скорость передачи данных будет слишком высокой для TCP (хотя сначала я бы попробовал TCP и подтвердил, что это проблема). Если вы выполняете потоковую передачу на том же компьютере, количество отбрасываемых пакетов должно быть минимальным, но добавление уровня отрицательного подтверждения позаботится об этом за вас.

person Robin    schedule 05.11.2008

Как насчет использования System.out и System.in?

Если это не подходит, то Sockets - ваш лучший выбор.

person Pyrolistical    schedule 05.11.2008

Если ваш процесс C ++ запускает процесс Java, он может извлечь выгоду из inheritedChannel. Кроме того, если процесс Java использует файл, я рекомендую изучить transferTo и transferFrom. При выполнении операций ввода-вывода из файла в файл они избегают ненужных переключений между пользователем и пространством ядра; та же оптимизация может сработать, если вы используете специальный канал сокета.

person erickson    schedule 05.11.2008

Я рекомендую «соединение» UDP, которое подтверждает каждый N-й пакет, полученный без ошибок, и запрашивает повторную передачу нескольких пропущенных пакетов.

person Ed.    schedule 06.11.2008

Я бы посоветовал не использовать JNI, потому что его очень сложно отлаживать. Если код C ++ выходит из строя или выдает неперехваченное исключение, ваша JVM выйдет из строя, и вы не поймете, почему.

person Dima    schedule 05.11.2008
comment
Это неправда. Вы можете отлаживать код JNI, подключившись к JVM. - person JesperE; 11.02.2009
comment
Вы правы, если работаете на ПК. В своей работе мы разрабатываем встраиваемую систему под управлением Linux, в которой, к сожалению, нет собственного отладчика. Даже gdb. Поэтому, когда код jni дает сбой, очень сложно понять, почему. - person Dima; 17.02.2009