Демонстрационная система SIN_CLIENT служит для иллюстрации того, как в системе CRW-DAQ можно организовывать распределенные системы управления, построенные по принципу клиент-сервер, с использованием технологии DIM.
Допустим, имеется сервер, то есть программа, которая умеет делать что-то содержательное, скажем, измерять и управлять физ. установкой. Допустим, также, что имеется несколько удаленных клиентов, то есть пользователей, которые могут располагаться как рядом с установкой и работать на локальной машине, так и быть удаленными пользователями в сети. В ряде случаев по условиям эксплуатации пользователи находиться рядом с компьютером просто не могут (радиация, химия, шум и т.д.). Возможно также, что несколько операторов в разных местах хотят наблюдать результаты измерений или управлять установкой. Таким образом, возникает СЕРВЕР - процесс, в котором работает программа измерений и произвольное число КЛИЕНТОВ - процессов, в которых запущен интерфейс пользователя. Клиент может быть локальным (тот же процесс) или удаленным (другой процесс на той же машине или процесс на другой машине в сети). Задача состоит в том, чтобы клиенты могли получать от сервера измеряемые данные, а также посылать серверу команды для управления установкой. Клиентская часть - интерфейс пользователя - должна строиться так, чтобы локальный клиент и удаленный клиент обрабатывались одинаково (избежать дурного дублирования). При этом сервер должен распознавать клиентов и иметь систему безопасности, то есть права клиентов должны быть разными, одним доступен только просмотр данных, другие могут управлять установкой. Такова, вкратце, формулировка задачи.
В данном демонстрационном примере СЕРВЕР умышленно примитивен: это просто генератор
двух якобы "измеряемых сигналов" - синусоиды sin_wave1 и косинусоиды sin_wave2,
с частотой sin_freq, амплитудой sin_ampl и искуственным шумом sin_noise,
которые моделируют "управляющие параметры" воздействия оператора.
При нажатии кнопки sin_start
программа
&sin_server начинает генерировать "измеренные" сигналы, при выключении кнопки
"измерения" останавливаются.
Кроме того, идет сохранение "измеряемых сигналов" в *.dat файлы по стандартной программе.
Для доступа клиентов к данным сервер публикует имя каталога sin_postbox,
в который он складывает *.dat файлы.
Клиенты на локальной или удаленной машине должны видеть кривые, значения управляющих параметров,
а также иметь возможность их менять (с системой прав доступа).
Если бы речь шла только о локальном клиенте, все было бы просто, события идентифицировались бы просто кнопкой и именем нажатого сенсора (clickbutton, clicksensor). Вся конфигурация и программа заняла бы пару десятков строк. На эту тему есть много примеров. С распределенной системой все сильно усложняется. Клиентов много, они работают одновременно на разных машинах, под разными пользователями, которые имеют разные права и жмут на все кнопки подряд во всех доступных окнах. Понятие события и его идентификация существенно усложняется. Этот факт не зависит от применяемой системы программирования, просто распределенные многопользовательские системы вообще по сути своей всегда сложнее локальных.
Событие типа "пользователь нажал сенсор" содержит теперь, как минимум, такие параметры:
Уже размер списка параметров события показывает, что задача непростая. Несколько упрощает дело то, что DIM берет на себя все "тяготы" сетевого обмена. Итак, начнем.
Сначала общая структура. Файлы !server.cfg и !client.cfg служат для загрузки соответственно сервера и удаленного клиента. Надо сказать, что локальный клиент включен в конфигурацию сервера. Удаленный клиент, даже если он запущен на той же машине, считается сетевым клиентом и обрабатывается совершенно аналогично удаленным клиентам на других машинах. Заметьте, что описание структур данных sin_common.cfg и клиентский интерфейс пользователя sin_client.cfg абсолютно одинаковы (включены как в серверную конфигурацию, так и в клиентскую), так и надо делать всегда. Отличие конфигураций состоит в том, что в серверной части работает конфигурация sin_server.cfg, которая содержит реальные "измерения", прием команд клиентов и передачу данных в сеть, а у клиента вместо этого работает "заглушка" sin_remote.cfg, которая обеспечивает прием данных из сети, то есть синхронизацию клиентской копии данных сервера, а также передачу в сеть команд от пользователя. Кроме того, в серверной части работает конфигурация sin_writer.cfg, которая сохраняет "измеренные" данные в архивные *.dat файлы.
Следует хорошенько уяснить, что в распределенной системе часто приходится работать с разными копиями одних и тех же данных. Локальный клиент, запущенный в рамках серверного процесса (в одной конфигурации с сервером), конечно, должен работать с данными сервера непосредственно. Удаленные клиенты имеют копию данных сервера, которая обновляется по сети через механизмы DIM. По этой причине имеет смысл выделить общие кривые и теги в отдельный файл, в данном случае это sin_common.cfg. Заметьте, что хотя файл "один и тот же", на самом деле удаленный клиент имеет совершенно другой (физически) набор данных, но того же типа, с той же структурой, с теми же именами. Тот факт, что файл конфигурации один и тот же, облегчает синхронизацию версий клиента и сервера. Обратите внимание, что помимо "измеряемых кривых" и "управляющих параметров" есть ряд служебных тегов - (sin_click,sin_notify) обеспечивают передачу пользовательских событий и уведомление сервера, (sin_txenable,sin_rxenable,sin_ioerrors) используются для управления приемо\передачей, (sin_wave1.x,sin_wave1.y,...) используются для передачи кривых (по два тега на кривую). Тут все вроде несложно.
Клиентский интерфейс sin_client.cfg и клиентская программа sin_client.pas в общем тоже не очень сложны. Хотя программа довольно большая, основная часть там - служебная, по сути неизменная, которая будет обычно просто копироваться без модификаций. Кроме очевидных вещей (мнемосхема, buttonclick,clicksensor) надо отметить следующее:
Серверная часть sin_server.cfg и "заглушка" sin_remote.cfg на стороне удаленного клиента посложнее. Однако обе содержат почти одинаковую часть - DIM сервер. По предлагаемому соглашению, каждая конфигурация имеет один и только один экземпляр DIM сервера по имени &DimSrv.
В серверной конфигурации sin_server.cfg DIM сервер
Надо отметить, что
Для передачи кривых сервер и клиент используют одну и ту же стандартную программу _DimCrvIo.pas. На каждую кривую Curve заводится пара тегов (Curve.X,Curve.Y), сервис содержит набор пар (X,Y). Однако конфигурация программы зеркальная - сервер работает как передатчик кривых dis_info, а клиент как приемник dic_info. Кроме того, программе требуются служебные теги (разрешение приемо-передачи, счетчик ошибок) и сообщения (они нужны для уведомления о приеме данных). При конфигурировании клиентского dic_info не забудьте послать сообщение "devmsg &SIN_WAVES_RX #SIN_WAVES_RX", а клиент должен содержать ссылку "msgRxUpdate=#SIN_WAVES_RX". Тогда при обновлении кривой клиент получит сообщение и обновит свою локальную копию кривых. О посылке кривых сервер заботится сам, автоматически.
Самой сложной частью системы является программирование сервера. Сервер, получив сообщение @click, декодирует и расшифровывает сообщение, выделяет его компоненты (Button, Sensor, Device, Window, Tag, Curve, Guard, User, Host, IP, MAC, Value, newValue). Получив данные, сервер анализирует права доступа пользователя. Права доступа задаются в таблице примерно такого вида:
[TrustedUsers] ;guard user host IP MAC user . . . . ; локальный user root alex crwbox * * ; root на crwbox\alex без проверки IP, MACКаждая строка таблицы содержит набор (Guard, User, Host, IP, MAC). Считается, что условие доступа выполнено, если уровень доступа не ниже указанного, а все остальные параметры удовлетворяют заданному шаблону. При этом в шаблоне символ (*) звездочки означает, что параметр может иметь любое значение, а символ (.) точки - текущее локальное серверное значение соответствующего параметра. Если пользователь удовлетворяет хотя бы одной строке таблицы, он получает права доступа. Если прав доступа не получено, сервер посылает уведомление об отказе в обслуживании запроса.
Если клиент имеет требуемые права доступа, сервер sin_server.pas начинает обработку сообщения. При этом следует использовать поля (Button, Sensor, Device, Window, Tag, Curve, Value, newValue) для анализа, что собственно произошло. Событие содержит достаточно обширный набор данных, поэтому можно обойтись одним потоком команд, даже если клиент содержит множество мнемосхем. Интересно также, что клиент по щелчку на сенсоре редактирования тега редактирует теги самостоятельно, а уже после редактирования передает событие с установленным параметром newValue, содержащим "желаемое" значение редактируемого параметра. Передается также значение Value в момент нажатия, так как локальная копия данных клиента может содержать устаревшие данные. Сервер, таким образом, имеет возможность узнать, какие данные имел клиент и что он хочет иметь в результате. В общем-то, действия сервера и уровень строгости его обработки - в руках программиста, более высокий уровень строгости и защиты влечет более сложный алгоритм обработки и более длительную отладку. При выборе алгоритма надо исходить из технических требований к конкретной системе.
Оценивая возможности и уровень сложности предложенной технологии, следует учитывать, что основная часть кода как клиента, так и сервера уже написана, в "порожденных" системах основная часть кода будет наследоваться с небольшими изменениями. Пример может быть достаточно легко расширен, при увеличении сложности клиента\сервера накладные расходы (код, обслуживающий обмен данными) расти сильно не будут. В коде клиента будет добавляться только обработка нажатий сенсоров, канал связи уже есть. В коде сервера будет добавляться содержательная обработка принятых команд и обработка данных. Поэтому, если один раз "продраться" через довольно непростой код примера, дальше все будет легко.