Эффективная передача данных с Java на C ++ в Windows - PullRequest
6 голосов
/ 06 ноября 2008

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

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

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

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

Ответы [ 11 ]

7 голосов
/ 06 ноября 2008

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

4 голосов
/ 06 ноября 2008

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

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

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

4 голосов
/ 06 ноября 2008

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

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

2 голосов
/ 18 сентября 2009

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

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

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

1 голос
/ 24 августа 2010

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

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

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

В целом, общая стратегия совместного использования двоичных данных (A / V-файлов, изображений и т. Д.) Из 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 tool ), UDP или TCP

1 голос
/ 07 ноября 2008

Если вы довольны написанием JNI, рассмотрите Boost.Interprocess . Это даст вам портативную общую память как в Linux, так и в Windows. Помните, что для чтения / записи разделяемой памяти нет ядра.

0 голосов
/ 06 ноября 2008

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

0 голосов
/ 06 ноября 2008

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

0 голосов
/ 06 ноября 2008

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

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

0 голосов
/ 06 ноября 2008

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

...