Взаимодействие двух приложений через локальные сокеты

Взаимодействие двух приложений через локальные сокеты

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

  • Сервер, который будет управлять несколькими различными приложениями(модулями) и выступать в роли моста между ними
  • Клиенты, обычные приложения, выполняющие свои специфические задачи.

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

Итак, приступим. Более подробная постановка задачи следующая: Есть несколько приложений(4) в виде исполняемых файлов, которые работают с общей базой данных, но выполняют специфические функции. Одно приложение «заведует» определенным кругом задач и предназначено для определенного круга специалистов. Периодически каждому приложению необходимо «общаться» с другим приложением для выполнения некоторых задач(Например документообороту необходимо связать документ с объектом на карте). Каждое приложение(модуль) должно запускаться единственным процессом в памяти. На одном рабочем месте может быть установлено от 1 до 4 модулей. Все модули на одном рабочем месте должны централизованно конфигурироваться.

Все модули изначально писались отдельно разными программистами и позже возникла задача их с кооперировать. Правда один момент все же облегчал задачу — все модули были написаны с использованием одного и того же фреймворка(Qt) и языка программирования(C++) и был доступ к исходникам. Я начал копать в сторону шин данных, но понял что для этой задачи это будет слишком сложно и грузно, т.к. мне не требовалось передавать какие-то сложные данные. Поэтому немного поразмыслив, решил поискать что-то более простое для этой задачи. Возникали различные идеи, использовать Windows API, передавать через файл и таймеры . Остановился на локальных сокетах и разделяемой памяти. Сокеты я использовал для того, чтобы передавать сигналы, а разделяемую память для контроля над всеми приложениями.

Сервер: При запуске серверного модуля приложения он проверяет все запущенные процессы, чтобы предотвратить создание копии своего процесса(В дальнейшем то же самое делается с клиентскими процессами).

Далее этот модуль ищет все доступные клиентские модули, чтобы включить соответствующие пункты меню. Ничего особенного, все по простому, ищутся исполняемые файлы, которые лежат рядом с серверным исполняемым файлом:

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

Далее в серверном модуле создается локальный сокет для ожидания входящих соединений от клиентских модулей

После запуска одному из клиентских приложений может понадобиться запросить какое-то действие у другого клиентского приложения или у сервера приложений. Для этого клиентское приложение создает соединение с локальным сокетом сервера

и упаковав и зашифровав простым алгоритмом обычную строку, передает массив байтов через сокет на сервер. Сериализованная строка содержит в себе следующую информацию:

  • Тип запроса(Запрос к серверу или к другому клиентскому модулю)
  • От какого модуля идет запрос
  • Сам запрос(Запрос оформляется в виде перечисления, которое включается при компиляции во все модули системы)
  • Параметры запроса(ключи, строки, служебная ифнормация и т.д.)

На серверной стороне строка расшифровывается и десериализуется. Далее считываются все параметры и в зависимости от типа, запрос обрабатывается или передается далее другому модулю.

Для сериализации и десериализации я написал простенький класс, который, принимая через методы все параметры запроса, формирует строку, разделенную условными символами, затем шифрует ее.

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

📎📎📎📎📎📎📎📎📎📎