Распределенные вычисления и технологии Inprise

Часть 5. Cоздание CORBA-серверов, переносимых на другие платформы, с помощью С++Builder 4

Наталия Елманова
Компьютер Пресс - CD, 1999, N 5
Copyright N.Elmanova & ComputerPress Magazine.

Данная статья посвящена возможностям C++Builder 4, связанным с созданием распределенных многоплатформенных систем. Она же является второй частью опубликованного в предыдущем выпуске журнала обзора, посвященного возможностям С++Builder 4.

  1. Постановка задачи
  2. Создание переносимого сервера функциональности
  3. Создание клиента с графическим пользовательским интерфейсом
  4. Создание переносимого клиентского приложения
  5. Несколько слов о серверах доступа к данным

Организация распределенных вычислений за последние два года стала весьма "модным" направлением в области проектирования информационных систем. Весьма популярны распределенные системы на основе COM и MIDAS (возможность создания которых появилась в предыдущей версии С++Builder). Однако нередко (особенно в случае повышенных требований к надежности подобного рода систем) возникает потребность использовать в качестве серверной части такой распределенной системы приложения, функционирующие на платформе, отличной от Windows (что исключает использование COM как специфичной для Windows технологии).

В этой связи следует заметить, что C++Builder позволяет генерировать код для таких переносимых приложений (естественно, за счет отказа от использования COM, VCL и Windows API). Соответственно в качестве технологии распределенных вычислений в этом случае используется многоплатформенная технология, не использующая специфику Windows. В последнее время наиболее часто для этой цели используется CORBA (Common Object Request Broker Architecture), спецификация которой создана консорциумом Object Management Group. В комплект поставки C++Builder Enterprise входит набор утилит и сервисов, предстаавляющих собой одну из реализаций этой спецификации - Inprise VisiBroker.

Данная часть обзора возможностей C++Builder 4 описывает создание сервера функциональности с использованием VisiBroker, переносимого на другие платформы, а также создание клиентских приложений для него (в том числе переносимых на другип платформы.

Постановка задачи

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

Пусть наше приложение имеет главную форму следующего вида (рис. 1):

Рис. 1. Интерфейс приложения, подлежащего разбиению на сервер и клиента

В нашем примере компонент TChart содержит одну серию (ее следует добавить вручную при создании формы).

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

//---------------------------------------------------------------------------
#include <vcl.h>
#pragma hdrstop

#include "Unit1.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;

//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
        : TForm(Owner)
{
}
//---------------------------------------------------------------------------

void __fastcall TForm1::BitBtn1Click(TObject *Sender)
{
  int i; double x1,y;
 for (i=1;i<60;i++)
 {
  x1=0.1*float(i-13);
  y=fun1(x1);
  Chart1->Series[0]->AddXY(x1,y,FloatToStr(x1),clWhite);
 }
}

 double fun1(double x)
{
 double r=x*x*x-5*x*x+3*x+5;
 return(r);
}

//---------------------------------------------------------------------------

Результатом работы такого приложения будет график нашего полинома, появляющийся при нажатии на кнопку "График" (рис. 2):

Рис. 2. То же приложение на этапе выполнения

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

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

Создание переносимого сервера функциональности

Итак, создадим CORBA-сервер, осуществляющий проведение расчетов. Сразу же заметим, что подобного рода серверы, как правило, не нуждаются в пользовательском интерфейсе. Поэтому мы вполне можем создать его как консольное приложение. Если при этом мы откажемся от использования VCL, код полученного сервера может быть скомпилирован любым другим компилятором C++ (в том числе, естественно, и компилятором для другой платформы). Консольные приложения есть единственный тип приложений, существующий для любых платформ, в отличие от приложений с графическим интерфейсом пользователя - последние требуют графических библиотек или операционных систем с GUI, и на все эти графические библиотеки и функции API подобных операционных систем нет никаких стандартов, в отличие от самого языка С++.

Иными словами, сервер может быть создан переносимым на другие платформы, что и будет сделано.

Для создания сервера выберем из репозитария объектов со страницы Multitier пиктограмму CORBA server (рис. 3):

Рис. 3. Выбор пиктограммы CORBA Server из репозитария объектов

После выбора пиктограммы в диалоговой панели CORBA Server Wizard выберем в качетсве типа приложения Console Application и отключим возможность использования VCL. Это позволит нам создать переносимый на другие платформы код (fig. 4):

Рис. 4. CORBA Server Wizard

Первое, с чего следует начинать создание распределенной системы, - это описание интерфейсов сервера. С этой целью используется язык IDL (Interface Definition Language), являющийся, по существу, стандартом для подобного рода описаний, не зависящим от языков программирования и платформ. Отметим, что существует несколько диалектов IDL (COM IDL, CORBA IDL, DCE IDL), имеющих некоторые различия. Естественно, мы будем использовать CORBA IDL. Так как мы еще не создали никакого IDL-описания, выберем опцию Add New IDL File. После нажатия на кнопку OK в окне редактора кода появится пустая страница для ILD-описания, куда можно ввести описание интерфейса нашего сервера.

interface b1 
{
 double fun1(in double x);
 } ; 

Далее следует скомпилировать IDL-файл. В действительности это не компиляция, а кодогенерация, в результате которой мы получим два модуля, fun1_s.cpp and fun1_c.cpp, содержащие stub-код и skeleton-код.

Что представляют собой stub-объект и skeleton-объект?

Все способы взаимодействия между серверами функциональности и их клиентами основаны на механизме вызовов удаленных процедур (RPC - Remote Procedure Calls) и маршалинга, представляющего солой обмен пакетами данных между объектом внутри клиента (stub-объектом) и объектом внутри сервера (skeleton-объектом). Skeleton-объект является представителем клиента внутри адресного пространства сервера. Обращаясь к нему, сервер "думает", что он имеет дело с локальным объектом. Stub-объект является представителем сервера внутри адресного пространства клиентского приложения, поэтому последнее также "думает", что вызывает методы локального объекта. В действительности так оно и есть, однако вместо истинной реализации (в нашем случае - вычисления значений функции) методы этого объекта осуществляют вызовы удаленных процедур и обмен пакетами данных с сервером (рис. 5):

Рис. 5. Взаимодействие сервера и клиента

Теперь можно вспомнить о реализации нашей функции. Для этого выберем со страницы Multitier репозитария объектов пиктограмму CORBA Object Implementation. В диалоговой панели CORBA Object Implementation Wizard выберем имя интерфейса (b1), а также определим имя модуля, содержащего реализацию, и имя класса CORBA-объектов. В данном примере мы описшем объект, экземпляр которого создается в момент старта сервера, так что сервер сразу же сможет принимать обращения клиентов (рис. 6):

Рис. 6. CORBA Object Implementation Wizard

Мы можем просмотреть изменения, внесенные в наше приложение этим экспертом. В частности, имеет смысл внести в код реализации нашего метода строки, ответственные за проведение расчетов (рис. 7):

Рис. 7. Добавление кода рализации функции в сгенерированный модуль

Теперь можно скомпилировать проект и закрыть его.

Перед созданием клиента мы должны запустить VisiBroker Smart Agent - службу каталогов CORBA, позволяющую осуществить доступ к CORBA-серверам. Теперь можно запустить наш сервер (желательно отдельно от среды разработки).

Теперь можно создавать клиенские приложения.

Создание клиента с графическим пользовательским интерфейсом

Для начала создадим клиентское приложение, представляющее собой обычное Windows-приложение с интерфейсом, похоржим на представленный на рис.2. Для этого выберем пиктограмму CORBA Client со страницы Multitier репозитария объектов C++Builder.

В этом примере мы будем использовать раннее связывание клиента с сервером (в этом случае можно достичь максимального быстродействия). Для этого выберем из меню среды разработки опцию "Edit/Use CORBA object". В соответствующем эксперте мы должны добавить к проекту тот же самый IDL-файл, что был создан при создании сервера, а также ответить на вопросы об именах объектов и переменных, в частности, об имени нового свойства формы, к которому следует обращаться, если нужно вызвать метод сервера (рис. 8):

Рис. 8. Определение свойств для доступа к CORBA-объекту в клиентском приложении

Далее можно создать интерфейс, сходный с приведенным на рис. 1, и создать обработчик события, связанного с нажатием на кнопку "График":

void __fastcall TForm1::BitBtn1Click(TObject *Sender)
{
 int i; double x1,y;
 for (i=1;i<60;i++)
 {
  x1=0.1*float(i-13);
  y=b1_1->fun1(x1);
  Chart1->Series[0]->AddXY(x1,y,FloatToStr(x1),clWhite);
         }
}

В результате получим тот же график, что и на рис.2.

Создание переносимого клиентского приложения

Теперь создадим клиентское приложение, переносимое на другие платформы. Это должно быть консольное приложение, не использующее VCL. В этом случае при создании клиента мы должны выбрать опцию "Console Application" и отменить опцию "Enable VCL" .

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

//---------------------------------------------------------------------------

#include <corbapch.h>
#pragma hdrstop

//---------------------------------------------------------------------------
#include "fun1_c.hh"

#include <corba.h>
#include <condefs.h>
USEIDL("corba\corba_rus\fun1.idl");
USEUNIT("corba\corba_rus\fun1_c.cpp");
USEUNIT("corba\corba_rus\fun1_s.cpp");
//---------------------------------------------------------------------------
#pragma argsused
int main(int argc, char* argv[])
{
        try
        {
                 // Initialize the ORB and BOA
                 CORBA::ORB_var orb = CORBA::ORB_init(argc, argv);
                 CORBA::BOA_var boa = orb->BOA_init(argc, argv);
                 a1_var a1_1 = a1::_bind("a1Obj");

cout<<"Our function table \n";
int i; double x1,y;
for (i=1;i<271;i++)
{
 x1=0.1*float(i);
  y=a1_1->fun1(x1);
  cout<<x1<<" "<<y<<"\n";
   }

        }
        catch(const CORBA::Exception& e)
        {
                 cerr << e << endl;
                 return(1);
        }
        return 0;
}
//---------------------------------------------------------------------------

В этом случае мы получим таблицу с результатами расчетов непосредственно на экране консольного приложения.

Отметим, что данное приложение можно скомпилировать любым компилятором С++, в том числе и компилятором для платформы, отличной от Windows.

Несколько слов о серверах доступа к данным

Серверы доступа к данным являются одним из наиболее популярных типов серверов middleware. Как создать переносимый сервер доступа к данным?

Наиболее популярный способ создания таких серверов - использование MIDAS и создание удаленных модулей данных как COM- или CORBA-объектов. В этом случае мы получим COM или CORBA-сервер, но это будет Windows-приложение, так как оно использует VCL, основанную на Windows API, и BDE, которая также представляет собой набор Windows-библиотек. Создание таких серверов более подробно будет рассмотрено в следующей статье данного цикла.

Если нам нужен переносимый сервер доступа к данным, он не должен использовать ни VCL, ни BDE. Как быть в этом случае?

Вспомним, что вся функциональность сервера доступа к данным - это набор SQL-запросов, и ничего более. Для MIDAS-серверов генератором запросов является BDE. Но выполнить запрос можно и другим способом! Например, всегда есть возможность использования низкоуровневого API клиентских частей серверных СУБД (например, Oracle Call Interface). Для большинства таких СУБД такие API существуют для многих платформ и содержат одни и те же функции. Использование таких API может показаться несколько утомительным, но в целом оно ненамного сложнее, чем написание других функций.

Российское представительство Inprise:
Тел. 7(095)238-36-11
e-mail: info@inprise.ru
http://www.inprise.ru