19 июля 2019 года    
Пятница | 22:50    
Главная
 Новости
Базы данных
Безопасность PC
Всё о компьютерах
Графика и дизайн
Интернет-технологии
Мобильные устройства
Операционные системы
Программирование
Программы
Связь
Сети
 Документация
Статьи
Самоучители
 Общение
Форум







Разделы / Программирование / Basic

DCOM или Компоненты типа Клиент-Сервер.

DCOM или Компоненты типа Клиент-Сервер

Хочу поделится собственным опытом написания, и главное настройки чуда, названного Микрософтом DCOM (Распределенные Компоненты - перевод вольный). Идея здравая и заключается она в том, что ваша Visual Basic программа может иметь удаленные компоненты. Здесь и далее под компонентами понимается приложение имеющее внутри обьект или обьекты , которые могут быть созданы и использованы "Извне". Если вы знакомитесь с обьектным Бэйсиком только сейчас - то компоненты легко создаются если вы выберете пункт ActiveX EXE или ActiveX DLL при старте среды Бэйсика. Но я отвлекся, Эти самые компоненты могут находится на вашем компьютере, и тогда никакой DCOM вам не нужен. Однако могут они лежать и на другой, доступной по сети машине. В этом случае удаленная компонента будет выполняться на той машине - на которой она лежит. Называться такакя компонента будет Сервером. Вот об этой то ситуации мы и поговорим. В самом деле Микрософт в Books-Online достаточно подробно говорит о создании компонентов, и даже приводит примеры. Рекомендую глянуть . Проблема только в том , что абсолютно не описана установка и настройка для правильной и надежной работы.

Итак, задача: Существует приложение, запускаемое с разных компьютеров (Multiuse Mode)и обращающающееся к базе данных расположенной на сервере. База данных - стандартная *.mdb . Необходимо внедрить в эту программу возможность контроля за количеством одновременно используемых копий программ, подсоединненных к серверу (Licence Control) , причем две или три копии программы запущенные одновременно на одном компьютере "съедают" только одну лицензию.

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

Как это реализованно. Компонента создается как ActiveX.EXE приложение, и в свойствах проекта (Закладка Component) сразу устанавливаем галочку, указывающую что это будет Remote Server, ActiveX Component и Binary Compatibility. Последнее совсем не помешает вам, когда вы будете устанавливать на сервере свою компоненту, тестировать, пересоздавать, и снова устанавливать. О создании несовместимой версии вас предупредят при компиляции - и это значит надо удалить все ссылки о старой версии, и зарегистрировать новую, но об этом чуть ниже. (Закладка General) - тут вы должны написать Project Name & Project Description. Startup Object - Sub Main. Поставьте галочку на Upgrade ActiveX Component и выбрерите Tread Pool = 1

На этом настройку проекта компоненты можно считать законченой . Сама компонента состоит из 2-х классов, Первый из которых (RLHolder) является "хранилищем" созданных коннектов (этот класс создается только изнутри компоненты, и количество его инстансов всегда не больше 1) В связи с этим свойство Instancing смело устанавливаем в Private. Сам по себе класс содержит одну коллекцию , в которую и добавляются-убавляются коннекты с приложением. Сами по себе коннекты выглядят как просто число типа Целое, от 1 и более, означающее количество копий запущеной на конкретном компьютере программы. Имя этого компьютера выступает в качестве "ключа" элемента коллекции. Методы и Свойства этого класса позволяют обращатся к указанной коллекции, добавлять, убавлять, считать коннекты.

Второй класс (RLMain) должен быть доступным для создания "извне" т.е. с удаленной машины. Его Instancing - Multiuse (возможность работать с одной копией сервера многим клиентам),

Так же в проекте есть модуль , в котором есть пустая процедура Sub Main, и Public переменная типа RLHolder. Инстанс первого класса создается при рождении второго - на событие Class_Initialize. Создается не просто так , а с проверкой - если переменная обьявленная в модуле уже ссылается на инстанс класса, то ничего не происходит, если нет - то создается новая, и таким образом единственная, инстанс.

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

Микрософт уверяет, что достаточно создать сетап-визардом простой сетап, указав , что компонента будет shared, и на сервере все само настроится. Частично он как всегда прав. Начнем с сети - если вы еще не установили TCP/IP протокол, то самое время сделать это. Этот протокол ДОЛЖЕН корректно работать на всех машинах которые будут использовать DCOM. Неплохо временно убить остальные протоколы, чтобы удостоверится в работоспособности TCP/IP. Далее - Если вы ставите эту удаленную компоненту на NT (а под Вин95 ее не рекомендуют ставить, хотя и должно работать) то для установки достаточно создать указанный сетап и выполнить его на NT машине. При последующих сменах версии вам необходимо обновлять сам *.exe файл , а также одноименные файлы с раширениями .tlb .vbr Если вы воспользовались сетапом , то все это будет лежать в system32 дирректории вашей NT. После этого разыщите в этой же директории файл dcomcnfg.exe и запустите его. В списке Application найдите свою компоненту - нам нужно поменять некоторые свойства - Закладка Location - поставить галочку на "Run App on this computer", Закладка Identity - выберите Interactive User. По умолчанию установленно другое свойство, и при запуске на каждого юзера будет создаваться своя копия компоненты в памяти (Инстанс) Т.е. мы потеряем то, к чему стремились - единая компонента, обслуживающая ВСЕХ пользователей. Закладку Security поправить просто - добавьте всюду EveryOne со всеми правами, и дело с концом. Жмем Apply и считаем настройку сервера выполненой. На будущее - не вредно заглянуть в vbr файл, там лежат ключи в регистри, которые описывают компоненту. Нередко после 3-4-5 обновлений, с нарушением cовместимости версий надо почистить реестр от всех этих ключей, и просто один раз запустить *.exe с компонентой. почистить реестр можно как ручками, так и с запуском утилиты regsvr32.exe с ключем /u

(В этом месте меня поправил Igor Martynenko, и он абсолютно прав)
Согласно документации Microsoft для регистрации ActiveX EXE необходимо либо запустить этот самый сервер и он сам зарегистрируется, либо запустить сервер с параметром /RegServer, т.е.
, MySvr.EXE /RegServer
Для разрегистрации сервера необходимо использовать параметр /UnRegServer соответственно, т.е MySvr.EXE /UnRegServer

Запуск regsvr32.exe с ключем /u помогает для разрегистрации *.dll

 

Работу с DCOM на клиентской машине надо начать с.... :-) установки DCOM на этой машине. Взять его можно на дистрибутивном диске Visual Basic 5, или на сайте у Микрософта. Этот файлик занимает чуть более одного мегабайта и является самоустанавливающимся архивом.(DCOM95.EXE) Если будут желающие, я выложу его на страничку. Не забывайте устанавливать его и на машите у покупателей вашей программы, без этого DCOM там не будет работать тоже - естественно, одной инсталяции достаточно до переустановки виндов. Инсталяция DCOM входит в поставку Windows NT, так что на ней об этом можно не беспкоится. К слову, я пробовал устанавливать DCOM98 (на машину где стоял пятый Бэйсик, и куча разного софта) и DCOM после этого не работал напрочь - вис, пришлось все вернуть назад, и поставить DCOM95. При том, что на рядом стоящей чистой машине с установленным VB6 он работает отлично.
По поводу клиента - эта программа должна делать собственно пару вещей - первое, создавать инстанс класса RLMain , передавать сведения об имени компьютера, на котором выполняется, запрашивать разрешено ли коннектится к серверу, и если да - то просто молча уступить дорогу основной программе. Клиентская часть у меня в примере оформлена как отдельная тестовая програмка, в самом деле она будет встроена в основной проект и предварять процедуру логона в систему. Соотвественно на выходе из программы нужно проверить запущена ли хотя бы одна копия этой программы, и если да - то просто уменьшить счетчик - определяющий сколько коннектов сделано с этого компьютера, если нет - то совсем убить коннекшн и этим освободить одну лицензию.

Как это реализовано - первая сложность с которой вы можете столкнуться - это обьявление типа обьектной переменной. Как вы несомненно помните, существует два типа "связывания" обьектной переменной с самим обьектом - "Раннее" и "Позднее" Первое отличается от второго скоростью выполнения , "Раннее" связывание работает быстрее. Второе отличие более неприятно в период разработки - Бэйсик не знает о каком обьекте идет речь и не подсказывает вам свойства и методы этого обьекта после того как вы ставите точку (а это непривычно и неудобно). Итак, достаточно обьявить
Dim obj as object
set obj = createObject("RLServ.RLMain")
И далее пользоваться пременной OBJ - как я указывал это второй метод связывания (Поздний) Почему это работает медленнее тоже обьяснимо - встретив в коде строку с просьбой создать обьект названного типа, Бэйсик лезет в регистри и ищет там идентификатор класса с таким именем, смотрит по этому идентификатору на что ссылается обьект (библиотеку типов например) и только после этого может приступать к созданию ссылки на такой обьект. В случае раннего связывания описанную работу Бэйск делает во время компиляции, и на стадии выполнения сразу создает ссылку. Почему я об этом рассказываю - вы должы понимать - что в сущности происходит при создани обьектов. Тут , пожалуй надо упомянуть о следующем - Если вы создаете ActiveX DLL, компилируете его , закрываете свой этот проект, открываете другой - в референсах вы сразу можете найти ссылку на свою DLL(там будет стоять то имя, которое вы написали в Description в свойствах проекта). Бэйсик регистрирует такие обьекты при компиляции, так же, как вы можете сделать это и сами , с помощью regsvr32.exe. Если же вы создаете ActiveX ЕХЕ , то ссылки вы не обнаружите. Ее еще просто нету. Для созданиия ссылки в Progect-References - надо зарегистрировать этот *.exe. Достарочно его один раз запустить , и все. Экзекутабл ActiveX являются саморегистрирующимися обьектами. Применительно к нашему проекту делать этого не нужно, более того крайне вредно. Если вы все- таки случайно запустили этот *.exe - ничего срашного - скопируйте в дирректорию вашего проекта из windows\system файлик regsvr32.exe и запустите его примерно так: regsvr32.exe /u MyServerName.exe
Следуя за моими извилистыми обьяснениями, вы уже поняли, что ваш удаленный сервер НЕ ДОЛЖЕН быть зарегистрирован на вашей машине - но я, конечно, обманул вас - должен. Только это должна быть регистрация УДАЛЕННОГО *.exe . Для этого существует как обычно несколько путей. Первый - создать визардом инсталяшку, указав в ней, что вы используете в проекте удаленный сервер. Указывать удаленный сервер , точнее его *.vbr файл надо ручками, сетап сам не определит наличие его в проекте. Далее надо выбрать тип доступа DCOM (реально там надо ответить NO, потому, что вопрос стоит использовать Ole Automation или нет - если нет - то это DCOM), напечатать имя компьютера, на котором будет запускаться сервер , и после создания достаточно выполнить этот сетап на машине клиента, регистрация будет произведена. Но, согласитесь - создавать и ранать сетап после каждого мало - мальски серьезеного изменения, пока вы создаете и отлаживаете программу несколько занудно, надоедливо и неэкономчно. Выход уже найден - программа CliReg32.exe. Она не поставляется с Windows, но ее можно найти где-то внутри бэйсиковского каталога. Не скажу точно, так как у меня сейчас установлен VB6, а в нем немного иначе все распологается , чем в пятом.
Найдите эту программу, и скопируйте ее в дирректорию с вашим сервером. В моем случае строка регистрации выглядит так
CLIREG32.EXE "rlserv.VBR" /s "ntserver40" /t "rlserv.TLB" /d /l
Где ntserver40 - зто сетевое имя компьютера, на котором будет пускаться сервер rlserv.exe
Назначение и имена ключей можно посмотреть запустив CLIREG32.EXE /? Обратите внимание на неестественный пробел между ключем, и параметром , который этот ключ описвает (напримет /s "ntserver40") Я провозился с этим добрых полчаса - пока не распотрошил сетап-визард в исходнике.
Если вы создаете несовместимый с прошлой версией сервер , старый нужно "разрегистрировать" используя эту же утилиту - только с ключем "/u". Только не нарушайте последовательность - получив предупреждение об несовместимости версий сервера - откажитесь от компиляции, разрегистрируйте сервер, откомпилируйте новую версию и зарегистрируйте его снова.
После всех этих извращений у нас уже готов к работе север, компьютер клиент, и может быть имеется некоторая ясность как писать программу клиент. Мы в общем -то остановились на обьявлении обьектной переменной. Обявлять ее просто как object не интересно (хотя и вполне возможно, и я сам так и делаю в примере), поэтому дарю вам хитрость, как обьявить переменную для "Раннего" связывания. Первое - вам надо убить все ссылки на сервер этот EXE сервер как локальный (regsvr32.exe /u), зарегистрировать как удаленный (см выше), пойти в Progect-References , нажать кнопку Browse, и выбрать *.tlb файл (в моем случае rlserv.TLB) Именно TLB, не EXE . После этого имеет право на жизнь такая строчка
dim obj as New RLServ.RlMain
Еще пару строк о клиенте - переменная obj обьявляется так, чтобы время ее жизни равнялось времени жизни приложения. Почему? Ну сами уже догадались , из условий задачи. Все остальные тонкости - можно уже относить к вашему стилю программирования и желанинию навесить на сервер какие-то дополнительные возможности. У меня, например, сервер честно возвращает время на машине сервере по свойству GetTime, что позволяет не заботится о синхронизации времени клиентов и сервера в сети. Так - же мой пример, до поднятия сервиса проверяет куда пользователь хочет коннектится, если он использует локальную датабэйз , сидящую на его собственном жестком диске - доступ происходит без контроля лицензий. Еще одно интересное свойство этой технологии - то что оно так же хорошо должно работать через RAS (доступ по модему , например).
Кстати, используя эту технологию можно достачно легко создавать асинхронный CallBack - т.е. сервер будет сам дергать клиента при наступлении опреденных событий. Причем не всех клиентов сразу - а только нужного. Я не пробовал сейчас это делать, да и в комплекте Бэйсика есть описание и пример по этому поводу - сходите в BooksOnline.
На этом позволю себе закончить. Пример
лежит здесь. Дополнения и пожелания принимаются.

Борис Рудой, 24 октября 1998г.

 

E-mail: b_rudoy@ultinet.net
 
 DCOM или Компоненты типа Клиент-Сервер.
Лента новостей


2006 (c) Copyright Hardline.ru