Взаимодействие двух приложений через локальные сокеты
Всем привет! Сегодня я решил написать о моей реализации взаимодействия двух приложений, выполняющихся в разных процессах через локальные сокеты. В свое время мне нужно было организовать следующую архитектуру приложения:
- Сервер, который будет управлять несколькими различными приложениями(модулями) и выступать в роли моста между ними
- Клиенты, обычные приложения, выполняющие свои специфические задачи.
Между двумя клиентскими приложениями необходимо было организовать простое взаимодействие — передачу сигналов в определенный момент и передачу ключей для выполнения определенных действий. Сервер приложений должен выполнять контролирующую функцию — не позволять запускать большее одной копии каждого клиентского приложения(модуля), также принимать сигналы и ключи для выполнения определенных действий и передавать сигналы между модулями
Итак, приступим. Более подробная постановка задачи следующая: Есть несколько приложений(4) в виде исполняемых файлов, которые работают с общей базой данных, но выполняют специфические функции. Одно приложение «заведует» определенным кругом задач и предназначено для определенного круга специалистов. Периодически каждому приложению необходимо «общаться» с другим приложением для выполнения некоторых задач(Например документообороту необходимо связать документ с объектом на карте). Каждое приложение(модуль) должно запускаться единственным процессом в памяти. На одном рабочем месте может быть установлено от 1 до 4 модулей. Все модули на одном рабочем месте должны централизованно конфигурироваться.
Все модули изначально писались отдельно разными программистами и позже возникла задача их с кооперировать. Правда один момент все же облегчал задачу — все модули были написаны с использованием одного и того же фреймворка(Qt) и языка программирования(C++) и был доступ к исходникам. Я начал копать в сторону шин данных, но понял что для этой задачи это будет слишком сложно и грузно, т.к. мне не требовалось передавать какие-то сложные данные. Поэтому немного поразмыслив, решил поискать что-то более простое для этой задачи. Возникали различные идеи, использовать Windows API, передавать через файл и таймеры . Остановился на локальных сокетах и разделяемой памяти. Сокеты я использовал для того, чтобы передавать сигналы, а разделяемую память для контроля над всеми приложениями.
Сервер: При запуске серверного модуля приложения он проверяет все запущенные процессы, чтобы предотвратить создание копии своего процесса(В дальнейшем то же самое делается с клиентскими процессами).
Далее этот модуль ищет все доступные клиентские модули, чтобы включить соответствующие пункты меню. Ничего особенного, все по простому, ищутся исполняемые файлы, которые лежат рядом с серверным исполняемым файлом:
После того, как пользователь выберет один из модулей, серверный модуль запускает клиентский модуль с параметрами через класс QProcess для того чтобы иметь контроль над процессом клиентского модуля и в случае завершения выполнения серверной части, клиентские модули также завершают свою работу.
Далее в серверном модуле создается локальный сокет для ожидания входящих соединений от клиентских модулей
После запуска одному из клиентских приложений может понадобиться запросить какое-то действие у другого клиентского приложения или у сервера приложений. Для этого клиентское приложение создает соединение с локальным сокетом сервера
и упаковав и зашифровав простым алгоритмом обычную строку, передает массив байтов через сокет на сервер. Сериализованная строка содержит в себе следующую информацию:
- Тип запроса(Запрос к серверу или к другому клиентскому модулю)
- От какого модуля идет запрос
- Сам запрос(Запрос оформляется в виде перечисления, которое включается при компиляции во все модули системы)
- Параметры запроса(ключи, строки, служебная ифнормация и т.д.)
На серверной стороне строка расшифровывается и десериализуется. Далее считываются все параметры и в зависимости от типа, запрос обрабатывается или передается далее другому модулю.
Для сериализации и десериализации я написал простенький класс, который, принимая через методы все параметры запроса, формирует строку, разделенную условными символами, затем шифрует ее.
В принципе вся система передачи работает довольно быстро и без отказов, возможно потому что данные, передаваемые через локальные сокеты не слишком велики и основная задача — передавать именно сигналы между модулями. Правда для добавления нового модуля нужно будет немного покодить, так как необходимо реализовать обработку сигналов, но это только если новый модуль участвует в обмене сигналами, если нет, то нужно будет только добавить проверку нового модуля на сервере. Вот в принципе и все. Конечно я опустил много деталей, возможно даже слишком много, буду рад комментариям и постараюсь ответить на все ваши вопросы