IPC с низкой задержкой между C ++ и Java - PullRequest
13 голосов
/ 30 мая 2011

Каков наилучший способ реализации C ++ / Java IPC для следующей ситуации?

(Кто-то недавно задал аналогичный вопрос , но мои требования более конкретны)

  1. У меня есть две программы - одна написана на C ++, другая на Java - которые должны общаться друг с другом. Оба работают на одном компьютере.

  2. Программы отправляют сообщения друг другу. Сообщения, как правило, короткие (менее нескольких сотен байтов), но потенциально могут иметь размер 100 КБ или более.

  3. Сообщения не нужно подтверждать (т. Е. Не модель запроса / ответа, такая как HTTP). Например, программа C ++ отправляет сообщение программе Java, и программа Java может ответить, отправив сообщение программе C ++ позднее - и наоборот.

  4. Идеальное решение будет иметь: а) очень низкую задержку, б) отсутствие проблем с безопасностью (пользователю не нужно разрешать открытие портов и т. Д.) И в) отсутствие зависимости от платформы.

Моей первой мыслью было использование сокетов - каждая программа действовала бы как сервер для другой. Сокеты имеют больше издержек, чем другие формы IPC, и я не знаю, как сервер сообщит клиенту номер порта, если я позволю системе автоматически назначать номера портов. Я также рассмотрел именованные каналы , но они не поддерживаются (по крайней мере, не всегда) на разных платформах. JNI выглядит как опция, но может ли она пересекать границы процесса?

Есть предложения?

Спасибо!

СЛЕДУЮЩИЕ ВОПРОСЫ

  1. Если я пойду с сокетами, нужно ли мне открывать два сокета, чтобы обеспечить асинхронную связь, как описано выше?

Ответы [ 6 ]

9 голосов
/ 30 мая 2011

Я бы посоветовал вам использовать TCP-сокеты .

Фактические накладные расходы на TCP-сокеты, по моему опыту, очень очень низкие по сравнению с нагрузкой других задачприложения, по крайней мере те, которые я использую для разработки.Я имею в виду, иногда, даже если задержка сокетов вдвое больше, чем задержка других механизмов IPC, в общем рабочем процессе они оказывают очень незначительное влияние.И это избавляет вас от необходимости создавать IPC между Java-приложением и C ++, что в конечном итоге потребует от вас использования конкретной библиотеки Java, которая использует JNI, с накладными расходами JNI и одной из самой библиотеки.

Я на самом деле измерил в моих приложениях Java, что влияние сборщика мусора гораздо важнее, чем задержка, вызванная " loopback " TCP-сокетами.

Более того, TCP-сокеты болеемасштабируемый (и портативный!), чем традиционный IPC.Что если в будущем вам придется запустить клиент и сервер на разных машинах?В сценарии «TCP-сокеты» вам придется выполнить 5-минутный хак, в сценарии «традиционный IPC» вам придется переписать весь материал IPC.

Однако,каков общий рабочий процесс вашего приложения?

Даже если подтверждение не требуется, я бы предложил использовать TCP (а не UDP), чтобы избежать несортированной доставки (что приводит к боли в заднице).когда речь идет о переупорядочении материала, который вы получили - некоторые из ваших сообщений имеют размер 100 КБ, и он не помещается в пакет UDP).

В ответ на ваш последний вопрос, чтобы сервер информировал клиента оport, вы можете просто заставить сервер запускать клиент с определенным параметром командной строки 'port', или заставить сервер сохранить небольшой файл в / tmp (или другой временный каталог) с номером порта, записанным внутри.

6 голосов
/ 30 мая 2011

Я слышал хорошие вещи о ZeroMQ специально для таких сценариев.В некоторых случаях он даже может быть быстрее, чем TCP.Короче говоря, конечно, не помешает попробовать.

4 голосов
/ 30 мая 2011

Альтернативой является использование файлов с отображенной памятью и сохранение их переносимости путем проверки настроек компилятора, если вы используете posix или нет. POSIX OS имеет mmap(), а в Windows вы бы использовали CreateFileMapping()

В библиотеке надстройки есть переносимая реализация для C ++, а в Java вы можете использовать FileChannel().

Эта страница хорошо объясняет, как это можно использовать для IPC http://en.wikipedia.org/wiki/Memory-mapped_file

3 голосов
/ 30 мая 2011

Когда вы говорите, очень низкая задержка, вы должны это квалифицировать. Вы можете отправлять сообщения через цикл Socket назад с RTT 20 микросекунд. Если это достаточно быстро, я бы сделал это.

Если это не достаточно быстро, я бы просто поместил C ++ в приложение Java и вызвал его через JNI. Это даст вам около 30 наносекунд RTT.

Проблема с использованием данных, отображаемых в памяти, заключается в правильной блокировке. Вы можете найти решение, которое работает в одной системе, но может не работать в других.

2 голосов
/ 30 мая 2011

Использование JNI позволит получить доступ ко всем возможностям в системе, а не только к тем, которые поддерживаются непосредственно в Java; это будет необходимо, например, если вы используете общую память. Однако JNI довольно дорогой.

Вопрос о латентности сложен, потому что ни один из механизмов, которые я знаю, не дает никаких гарантий. В общем, самой быстрой, вероятно, была бы какая-то форма совместной памяти, использующая сигналы для пробуждения другого процесса при наличии данных. Это потребует использования JNI на стороне Java, но, если все сделано правильно, это, вероятно, все равно даст наименьшую задержку - правильное выполнение (гарантируя, что сообщения не будут потеряны) может быть далеко не тривиальным. Платформы на основе Unix поддерживают сигналы очередей и обрабатывают их как события в отдельном потоке; Я не знаю о Windows.

Кроме того, именованный канал, как правило, довольно эффективен; задержка может быть такой же, как общая память, но для прохождения данных требуется больше времени (поскольку они должны быть скопированы через систему). И должно быть возможно получить к нему доступ непосредственно из Java, без использования JNI. В Unix также возможно настроить сокеты так, чтобы они реагировали так же быстро (фактически, это то, что именованный канал находится под капотом); Однако я не знаю, поддерживает ли интерфейс Java эти параметры конфигурации, и опять же, я не знаю, доступны ли они под Windows.

1 голос
/ 30 мая 2011

Альтернативой может быть использование встроенной БД (поскольку вы рассматриваете несколько IPC, я предполагаю, что оба приложения находятся на одной машине).

Я использую для работы над приложением ранее, где c ++приложение извлекает данные из всех видов каналов и помещает их в БД (база данных в памяти; TimesTen).Чтобы отобразить эти данные пользователю, приложение Java запросит их у БД.

Для вашего использования, я не знаю, захотите ли вы рассмотреть Oracle's Timesten, но вы могли бы какхорошо используйте встроенную БД Беркли.

...