В этой статье рассмотрены некоторые вопросы, встречающиеся при реализации распределенных систем,
построенных на технологии CORBA.
Примеры ориентированы на OmniORB 3.0.
Общая инфомация
Общая схема клиент-серверного обмена
Рассмотрим часто используемый порядок работы клиента и сервера.
На рисунке ниже объект Client находится на Клиенте, объекты MyFactory и Connection - на Сервере.
Connect()
- Программа-Клиент каким-то методом (рассмотрены ниже) получает и активизирует ссылку на фабрику объектов.
GetNewConnection()
- Клиент вызывает у фабрики метод создания нового обекта Connection (Соединение).
Create() - объект-фабрика создает новый объект Соединение.
GetReference() - получает у вновь созданного объекта его ссылку.
ReturnReference() - возвращает ссылку Клиенту.
DoSome_Job() - Клиент работает с объектом - вызывает некоторае функции и пр.
Disconnect() - Клиент отключается от объекта Соединение.
Disconnect() - Клиент отключается от фабрики объектов.
Представленная схема позволяет:
Проводить аутентификацию клиентов на этапе создания Соединения
путем передачи дополнительных параметров функции GetNewConnection().
Сосредоточить ведение учета работы (log) в объекте Соединение.
Удобно контролировать неактивных клиентов
(например, из-за разрыва связи через интернет)
и принимать соответствующие меры.
О POA
POA (Portable Object Adapter) создает объекты c характеристиками,
которые были заданы на стадии создания самого POA
(или "временные" (transient), или "долгоживущие" (persistent)).
Во "временной" (transient) ссылке (IOR) присутствует информация о:
Host IP
Host port
POA name
Object ID
Случайная информация
т.е., при следующем использовании такой ссылки, если сервер перезепущен и объект заново создан,
этот объект клиентом не будет найден (во всяком случае, так должно быть).
"Долгоживущие" (persistent) ссылки не содержат "случайной информации",
поэтому могут быть использованы после перезапуска сервера.
"Долгоживущие" ссылки создаются при помощи POA с PortableServer::PERSISTENT lifespan_policy[1].
В нашем случае объект MyFactory должен иметь постоянную ссылку, Connection - временную.
Типичные проблемы
Получение IOR фабрики
Существует несколько способов получения IOR объекта.
Преобразование в SIOR (Stringified IOR) и обратно.
При запуске сервер преобразует IOR объекта в строку с помощью функции object_to_string(),
Например
// Создаем и активизируем объект
MyFactory_impl* myFactory = new MyFactory_impl();
PortableServer::ObjectId_var myFactoryid = pers_poa->activate_object(myFactory);
myFactory->_remove_ref();
публикует полученный полученный файл в доступном для клиента месте,
клиент читает SIOR и с помощью функции string_to_object() преобразует в ссылку на объект.
Эта функция предоставляет клиенту набор ссылок на несколько предопределенных служб
(Naming, Trading, Interface Repository и т.п.).
Эти службы можно использовать для получения необходимых ссылок.
Возвращаемые значения resolve_initial_references необходимо настраивать на каждой клиентской машины.
(Для каждого ORB по-разному)[2,разд.4.2].
Например, один из методов настройки resolve_initial_references для получения ссылки на
NameService [2,разд.4.2.1] - поместить в файл C:\omniORB.cfg:
NAMESERVICE IOR:далее_sior_полученный_методом_1
Поиск в каком - нибудь хранилище ссылок.
Например, Naming service [2,разд.2.10],[3],[4] или Trading service. Для получения ссылки
на необходимое хранилище придется воспользоваться методом 1 или 2.
Использование INS POA
INS (Interoperable Name Service) POA [2,разд.4.5],[5] позволяет создавать объекты
с унифицированными идентификаторами ресурсов (Uniform Resource Identifierkeys - URI)
вида "corbaloc::hostname:port/Object_key".
Это можно сделать (в omniORB) при помощи специального POA "omniINSPOA",
полученного посредством resolve_initial_references().
Этот POA позволяет создавать объекты ссылки которых содержат только
переданный POA при создании ID объекта.
Например
// у сервера в параметрах командной строки должны присутствовать: -ORBpoa_iiop_port 1234
// где 1234 - номер порта, на котором сервер будет принимать запросы
orb =
CORBA::ORB_init(argc, argv, "omniORB3");
// ins_poa - для того, чтоб клиент смог подконнектиться к серверу по имени(IP) и порту
CORBA::Object_var obj =
orb->resolve_initial_references("omniINSPOA");
PortableServer::POA_var ins_poa =
PortableServer::POA::_narrow(obj);
PortableServer::POAManager_var ins_pman =
ins_poa->the_POAManager();
ins_pman->activate();
// Always use the same object id.
PortableServer::ObjectId_var oid =
PortableServer::string_to_ObjectId("myPersistentFactory");
// Activate the Creator object...
CmyFactory_impl* myFactory = new CmyFactory_impl();
ins_poa->activate_object_with_id(oid,myConn_Creator);
myFactory->_remove_ref();
Со стороны клиента необходимо указать имя сервера и порт.
ID объекта известен заранее.
Если и клиент и сервер работают на одном компьютере,
то в качестве имени сервера можно использовать "localhost".
Контроль коннекта со стороны сервера и сборка мусора
Под сборкой мусора будем понимать удаление сервантов из памяти
процесса сервера после окончания необходимости в соответствующих (transient) объектах.
Call-Back объекты.[6]
Отдельным тредом запускается контроллер Call-Back объекта.
Если Call-Back объект не отвечает, удаляем сервант серверного объекта.
Если использовать CallBack-объекты, то при работе через интернет клиент,
спрятанный за прокси, виден не будет,
т.к в ссылку на CallBack попадает IP адрес локальной сети.
При работе внутри локальной сети этот механизм вполне работоспособен.
Реализация метода Deactivate() у объекта.
Например
void Connection_impl::Deactivate()
{
PortableServer::POA_var poa = _default_POA();
// если объект использует именно _default_POA()
PortableServer::ObjectId_var oid =
poa->servant_to_id(this);
poa->deactivate_object(oid);
// Если объект не отнаследован от PortableServer::RefCountServantBase, то раскомментировать след. строку
// delete this;
}
При разрыве коннекта (смерти клиента) этот метод никогда
не будет вызван и объект останется висеть в памяти сервера на веки вечные.
Expired time accounting
Суть метода состоит в в удалении сервером объектов,
последнее обращение к которым произошло давно.
Каждый серверный объект имеет атрибут "время последнего обращения".
При реализации функций серванта этот атрибут каждый раз устанавливается в текущее время
На сервере хранится коллекция ссылок на клиентские объекты.
Отдельный поток регулярно проходит по этим ссылкам,
и если время последнего обращения к объекту было давно, то деактивизирует
объект и удаляет соответствующий сервант.
Список дополнительных источников информации
Пример poa\persistent_objref из поставки omniORB 3.0
"The omniORB version 3.0, User’s Guide" .pdf версия
Пример echo из поставки omniORB 3.0: eg3_clt, eg3_impl
README.win32 из поставки omniORB 3.0, раздел "Running omniNames as an NT service"