[an error occurred while processing this directive]
[an error occurred while processing this directive]


Некоторые особенности построения систем с использованием технологии CORBA

Ростислав А. Глухов ross2204@mail.ru

В этой статье рассмотрены некоторые вопросы,
встречающиеся при реализации распределенных систем,
построенных на технологии CORBA.
Примеры ориентированы на OmniORB 3.0.

Общая инфомация

Общая схема клиент-серверного обмена

Рассмотрим часто используемый порядок работы клиента и сервера. На рисунке ниже объект Client находится на Клиенте, объекты MyFactory и Connection - на Сервере.

Sample Sequence Diagram

  1. Connect() - Программа-Клиент каким-то методом (рассмотрены ниже) получает и активизирует ссылку на фабрику объектов.

  2. GetNewConnection() - Клиент вызывает у фабрики метод создания нового обекта Connection (Соединение).
    • Create() - объект-фабрика создает новый объект Соединение.
    • GetReference() - получает у вновь созданного объекта его ссылку.
    • ReturnReference() - возвращает ссылку Клиенту.

  3. DoSome_Job() - Клиент работает с объектом - вызывает некоторае функции и пр.

  4. Disconnect() - Клиент отключается от объекта Соединение.

  5. Disconnect() - Клиент отключается от фабрики объектов.

Представленная схема позволяет:

О POA

POA (Portable Object Adapter) создает объекты c характеристиками, которые были заданы на стадии создания самого POA (или "временные" (transient), или "долгоживущие" (persistent)).

Во "временной" (transient) ссылке (IOR) присутствует информация о:

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

"Долгоживущие" (persistent) ссылки не содержат "случайной информации", поэтому могут быть использованы после перезапуска сервера. "Долгоживущие" ссылки создаются при помощи POA с PortableServer::PERSISTENT lifespan_policy[1].

В нашем случае объект MyFactory должен иметь постоянную ссылку, Connection - временную.

Типичные проблемы

Получение IOR фабрики

Существует несколько способов получения IOR объекта.

  1. Преобразование в 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();

    // Получаем stringified IOR объекта
    CORBA::Object_var obj = myFactory->_this();
    CORBA::String_varsior(orb->object_to_string(obj));
    // Выводим stringified IOR в файл
    ofstream ior_file("ior_file.txt");
    ior_file << "'" << (char*)sior << "'" << endl;

    PortableServer::POAManager_var pman = pers_poa->the_POAManager();
    pman->activate();

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

    Например
    // Читаем ссылку из файла
    ifstream ior_file("ior_file.txt");
    char buf[200];
    ior_file >> buf;
    // Активизируем ссылку
    CORBA::Object_var obj = orb->string_to_object(buf);
    MyFactory_var MyFactoryref = MyFactoryEcho::_narrow(obj);

  2. Вызов resolve_initial_references

    Эта функция предоставляет клиенту набор ссылок на несколько предопределенных служб (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

  3. Поиск в каком - нибудь хранилище ссылок.

    Например, Naming service [2,разд.2.10],[3],[4] или Trading service. Для получения ссылки на необходимое хранилище придется воспользоваться методом 1 или 2.

  4. Использование 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 объекта известен заранее.

    Например : функция возвращает ссылку на объект
    CORBA::Object_ptr getObjectReference2(CORBA::ORB_ptr orb, char *hostname, int port)
    {
    try {
    char cstr[8];
    char sstr[1000];
    strcpy(sstr, "corbaloc::");
    strcat(sstr, hostname);
    strcat(sstr, ":");
    if(!port)
    port = 3000;
    strcat(sstr, itoa(port,cstr,10));
    strcat(sstr, "/myPersistentFactory");
    // sstr: "corbaloc::host_name:port_number/myPersistentFactory"
    // меняются: host_name,port_number

    returnorb->string_to_object(sstr);
    }catch(CORBA::COMM_FAILURE& ex){
    cerr << "Caught system exception COMM_FAILURE -- unable to contact the remote server." << endl;
    }
    catch(CORBA::SystemException & ) {
    cerr << "Caught a CORBA::SystemException while contacting remote server." << endl;
    }
    return CORBA::Object::_nil();
    }

    Если и клиент и сервер работают на одном компьютере, то в качестве имени сервера можно использовать "localhost".

Контроль коннекта со стороны сервера и сборка мусора

Под сборкой мусора будем понимать удаление сервантов из памяти процесса сервера после окончания необходимости в соответствующих (transient) объектах.

  1. Call-Back объекты.[6]

    Отдельным тредом запускается контроллер Call-Back объекта. Если Call-Back объект не отвечает, удаляем сервант серверного объекта.

    Если использовать CallBack-объекты, то при работе через интернет клиент, спрятанный за прокси, виден не будет, т.к в ссылку на CallBack попадает IP адрес локальной сети. При работе внутри локальной сети этот механизм вполне работоспособен.

  2. Реализация метода 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;

    }

    При разрыве коннекта (смерти клиента) этот метод никогда не будет вызван и объект останется висеть в памяти сервера на веки вечные.

  3. Expired time accounting

    Суть метода состоит в в удалении сервером объектов, последнее обращение к которым произошло давно.

Список дополнительных источников информации

  1. Пример poa\persistent_objref из поставки omniORB 3.0
  2. "The omniORB version 3.0, User’s Guide" .pdf версия
  3. Пример echo из поставки omniORB 3.0: eg3_clt, eg3_impl
  4. README.win32 из поставки omniORB 3.0, раздел "Running omniNames as an NT service"
  5. Исходный текст программы omniNames
  6. Пример call_back из поставки omniORB 3.0

[an error occurred while processing this directive]

[an error occurred while processing this directive]