Динамическое создание IPC-каналов при разработке на языке С++ с использованием NameServer
Использование системной программы NameServer является устаревшим способом динамического создания IPC-каналов. При создании нужно использовать системную программу DCM (см. "Динамическое создание IPC-каналов при разработке на языке C++ с использованием DCM").
Динамическое создание IPC-канала на стороне клиента включает следующие шаги:
- Подключить к клиентской программе сгенерированный заголовочный файл описания (
*.edl.cpp.h). - Подключить сгенерированные заголовочные файлы описаний используемых интерфейсов (
*.idl.cpp.h). - Подключить заголовочные файлы из состава KasperskyOS SDK:
/opt/KasperskyOS-Community-Edition-<platform>-<version>/sysroot-*-kos/include/kosipc/application.h/opt/KasperskyOS-Community-Edition-<platform>-<version>/sysroot-*-kos/include/kosipc/make_application.h/opt/KasperskyOS-Community-Edition-<platform>-<version>/sysroot-*-kos/include/kosipc/connect_dynamic_channel.h
- Создать объект приложения, вызвав функцию
kosipc::MakeApplicationAutodetect(). (Также можно использовать функцииkosipc::MakeApplication()иkosipc::MakeApplicationPureClient().) - Создать и инициализировать прокси-объект для службы, реализующей требуемый интерфейс. Полный список служб с требуемым интерфейсом можно получить с помощью сервера имен (системная программа
NameServer). Подробнее см. "Динамическое создание IPC-каналов (cm_api.h, ns_api.h)".- Создание прокси-объекта для службы, реализующей требуемый интерфейс и найденной первой среди опубликованных служб на сервере имен.
- Вызвать функцию
MakeProxy(). - В качестве входного параметра функции
MakeProxy()использовать вызов функцииkosipc::ConnectPublishedService(). - Передать функции
kosipc::ConnectPublishedService()указатель на имя интерфейса служб.
- Вызвать функцию
- Создание прокси-объекта для любой службы из списка служб, реализующих требуемый интерфейс и опубликованных на сервере имен.
- Подключиться к серверу имен вызовом функции
NsCreate(). - Получить полный список служб, реализующих требуемый интерфейс и опубликованных на сервере имен, использовав в цикле функцию
NsEnumServices(). Для каждой службы из этого списка функцияNsEnumServices()возвращает указатель на имя сервера (параметрserver) и указатель на квалифицированное имя службы (параметрservice). - Из полученного на предыдущем шаге списка выбрать службу согласно реализуемой логике разрабатываемого решения.
- Вызвать функцию
MakeProxy(). - В качестве входного параметра функции
MakeProxy()использовать вызов функцииkosipc::ConnectDynamicChannel(). - В функцию
kosipc::ConnectDynamicChannel()передать указатели на имя сервера и квалифицированное имя службы, полученные на шагеbтекущего списка.
- Подключиться к серверу имен вызовом функции
- Создание прокси-объекта для службы, реализующей требуемый интерфейс и найденной первой среди опубликованных служб на сервере имен.
После успешной инициализации прокси-объекта клиенту доступен вызов методов службы.
Пример
NsHandle ns;
// Подключение к серверу имен
Retcode rc = NsCreate(RTL_NULL, INFINITE_TIMEOUT, &ns);
char serverName[kl_core_Types_UCoreStringSize];
char endpointName[kl_core_Types_UCoreStringSize];
// Получение указателей на имя сервера и квалифицированное имя службы
rc = NsEnumServices(
ns, interfaceName, 0,
serverName, kl_core_Types_UCoreStringSize,
endpointName, kl_core_Types_UCoreStringSize);
// Создание и инициализация объекта приложения
kosipc::Application app = kosipc::MakeApplicationAutodetect();
// Создание и инициализация прокси-объекта
auto proxy = app.MakeProxy<Writer>(
kosipc::ConnectDynamicChannel(serverName, endpointName))
// Вызов метода требуемой службы
writer->DoSomeWork();
Динамическое создание IPC-канала на стороне сервера включает следующие шаги:
- Подключить к серверной программе сгенерированный заголовочный файл (
*.edl.cpp.h), содержащий описание компонентной структуры сервера, включая все предоставляемые службы. - Подключить заголовочные файлы из состава KasperskyOS SDK:
/opt/KasperskyOS-Community-Edition-<platform>-<version>/sysroot-*-kos/include/kosipc/application.h/opt/KasperskyOS-Community-Edition-<platform>-<version>/sysroot-*-kos/include/kosipc/event_loop.h/opt/KasperskyOS-Community-Edition-<platform>-<version>/sysroot-*-kos/include/kosipc/make_application.h/opt/KasperskyOS-Community-Edition-<platform>-<version>/sysroot-*-kos/include/kosipc/root_component.h/opt/KasperskyOS-Community-Edition-<platform>-<version>/sysroot-*-kos/include/kosipc/serve_connection_requests.h/opt/KasperskyOS-Community-Edition-<platform>-<version>/sysroot-*-kos/include/kosipc/serve_dynamic_channel.h/opt/KasperskyOS-Community-Edition-<platform>-<version>/sysroot-*-kos/include/kosipc/service_list.h/opt/KasperskyOS-Community-Edition-<platform>-<version>/sysroot-*-kos/include/kosipc/simple_connection_acceptor.h/opt/KasperskyOS-Community-Edition-<platform>-<version>/sysroot-*-kos/include/kosipc/ns_service_publisher.h>
- Создать классы, содержащие реализации интерфейсов, которые сервер предоставляет в виде служб. Создать и инициализировать объекты этих классов.
- Создать объект приложения, вызвав функцию
kosipc::MakeApplicationAutodetect(). - Создать и инициализировать объект класса
kosipc::components::Root, который описывает структуру компонентов и служб сервера. Эта структура генерируется из описаний в CDL- и EDL-файлах. - Связать объект класса
kosipc::components::Rootс объектами классов, созданными на шаге 3. - Создать и инициализировать объект класса
kosipc::EventLoop, который реализует цикл диспетчеризации входящих IPC-сообщений, вызвав функциюMakeEventLoop(). В качестве входного параметра функцииMakeEventLoop()использовать вызов функцииServeDynamicChannel(). В функциюServeDynamicChannel()передать объект классаkosipc::components::Root, созданный на шаге 5. - [Опционально] Создать и инициализировать объект класса
kosipc::ServiceList, который содержит список служб для публикации на сервере. Для добавления служб в список использовать методAddServices(). Использование объекта классаkosipc::ServiceListпозволяет, например, разделять компоненты и службы сервера на группы или публиковать службы под разными именами (пример кода см. ниже). - Создать и инициализировать объект класса
kosipc::NsServicePublisher, который предназначен для публикации служб на сервере. В качестве входных параметров конструктору передать:- объект приложения из шага 4;
- объект класса
kosipc::components::Root, созданный на шаге 5, или объект классаkosipc::ServiceList, сформированный на шаге 8.
Если публикация служб на сервере имен не требуется, создать и инициализировать объект класса
kosipc::CmServicePublisher(пустой публикатор). В качестве входных параметров конструктору передать:- объект приложения из шага 4;
- объект класса
kosipc::components::Root, созданный на шаге 5, или объект классаkosipc::ServiceList, сформированный на шаге 8.
Объекты, создаваемые на шагах 9-11, должны быть созданы после создания цикла диспетчеризации входящих IPC-сообщений (см. шаг 7).
Библиотека
kosipcобеспечивает гарантию: при создании объекта классаkosipc::NsServicePublisherвсе переданные ему службы публикуются на сервере имен, а при разрушении объекта – снимаются с публикации. - Создать и инициализировать объект, который реализует обработчик приема входящих запросов на динамическое создание IPC-канала.
При создании объекта можно использовать класс
kosipc::SimpleConnectionAcceptor, который является стандартной реализацией интерфейсаkosipc::IConnectionAcceptor. (Интерфейсkosipc::IConnectionAcceptorопределен в файле/opt/KasperskyOS-Community-Edition-<platform>-<version>/sysroot-*-kos/include/kosipc/connection_acceptor.h.) В этом случае обработчик будет реализовать следующую логику: если запрашиваемая клиентом служба опубликована на сервере, то запрос от клиента будет принят, иначе отклонен.Если необходимо создать собственный обработчик, то следует реализовать свою логику обработки запросов в методе
OnConnectionRequest(), унаследованном от интерфейсаkosipc::IConnectionAcceptor. Этот метод будет вызываться сервером при получении от клиента запроса на динамическое создание IPC-канала. - Создать объект класса
kosipc::EventLoop, который реализует цикл приема входящих запросов на динамическое создание IPC-канала, вызвав функциюMakeEventLoop(). В качестве входного параметра функцииMakeEventLoop()использовать вызов функцииServeConnectionRequests(). В функциюServeConnectionRequests()передать объекты, созданные на шаге 9 и 10. Объекты можно передать с использованием умных указателей (std::shared_ptr)или обычных указателей. В первом случае библиотекаkosipcберет на себя управление временем жизни объектов. Во втором случае ответственность остается за разработчиком: необходимо гарантировать, что объекты, созданные на шагах 9 и 10, не будут уничтожены до завершения работы объектаkosipc::EventLoop.Цикл приема входящих запросов на динамическое создание IPC-канала может быть только один. Цикл должен работать в одном потоке. После создания и запуска циклов не требуется синхронизации между потоками, в которых циклы исполняются.
- Запустить цикл диспетчеризации входящих IPC-сообщений в отдельном потоке, вызвав метод
Run()объектаkosipc::EventLoop. - Запустить в текущем потоке цикл приема входящих запросов на динамическое создание IPC-канала, вызвав метод
Run()объектаkosipc::EventLoop. До запуска этого цикла клиентские процессы блокируются при создании прокси-объекта в ожидании ответа от сервера на запрос подключения.
Пример кода для объединения набора компонентов и служб сервера в список объектов типа ServiceList с помощью метода AddServices():
// Создание объекта приложения
kosipc::Application app = kosipc::MakeApplicationAutodetect();
// Создание и инициализация объекта group_1
kosipc::components::Root group_1;
group_1.component1.endpoint1 = &impl_1;
group_1.component2.endpoint2 = &impl_2;
// Создание цикла диспетчеризации входящих IPC-сообщений
kosipc::EventLoop loop1 = app.MakeEventLoop(ServeDynamicChannel(group_1));
// Создание и инициализация объекта group_2
kosipc::components::Root group_2;
group_2.component3.endpoint1 = &impl_3;
group_2.component4.endpoint2 = &impl_4;
// Создание цикла диспетчеризации входящих IPC-сообщений
kosipc::EventLoop loop2 = app.MakeEventLoop(ServeDynamicChannel(group_2));
// Создание и инициализация объекта group_3
kosipc::components::Root group_3;
group_3.component5.endpoint1 = &impl_5;
// Создание цикла диспетчеризации входящих IPC-сообщений
kosipc::EventLoop loop3 = app.MakeEventLoop(ServeDynamicChannel(group_3));
// Создание списка объектов
ServiceList endpoints;
endpoints.AddServices(group_1);
endpoints.AddServices(group_2);
endpoints.AddServices(group_3.component5.endpoint1, "SomeCustomEndpointName");
// Создание объекта, реализующего публикацию служб на сервере
kosipc::NsServicePublisher publisher(app, endpoints);
// Создание объекта, реализующего обработчик приема входящих запросов
// на динамическое создание IPC-канала
kosipc::SimpleConnectionAcceptor acceptor(app, endpoints);
// Создание объекта, реализующего цикл приема входящих запросов
// на динамическое создание IPC-канала
kosipc::EventLoop loopDynamicChannel = app.MakeEventLoop(ServeConnectionRequests(&acceptor, &publisher));