суббота, 28 августа 2010 г.

Часть 2: Система удаленного управления приложениями персонального компьютера с помощью мобильных устройств

1 Серверное приложение

clip_image002
Рисунок 1. Диаграмма связи классов серверного приложения
Рассмотрим более подробно исходные классы серверного приложения и связи между ними.
В данном приложении была реализована популярная сейчас модель программирования Model – View – Controller, когда логика приложения и его отображение разделены в программном коде, для большей расширяемости, удобстве внесения изменений, портировании. Так же было решено взаимодействие между Model и View-Controller сделать только в двух классах (Engine и UIEngine), являющихся посредниками между остальными классами, реализация взаимодействия была сделана в стиле данного языка программирования и его средствами – событиями и обработчиками событий.
Классы:
Ø ProgramStart
Стартовым классом программы является ProgramStart. Он запускает основной цикл обработки сообщений системы приложением и передает управление классу UIEngine
Ø UIEngine
UIEngine – так же как и класс Engine, сделан с применением паттерна проектирования Singleton, позволяющего получать доступ к классу из любой части кода без явного создания и хранения на этот класс ссылки через поле Instance, при обращении к которому происходит неявное создание объекта класса. Этот класс отвечает за управлениями окнами приложения и обработкой части событий, происходящих на этих формах, таких как, например, нажатие кнопки.
Данный класс содержит открытый метод Run, вызываемый в предыдущем классе, при запуске программы. В этом методе происходит создание основных диалоговых окон приложения. Они создаются только один раз, далее показываются или скрываются в зависимости от действий пользователя.
При вызове конструктора метода (при неявном создании), происходит добавление обработчиков событий класса Engine, описанного ниже. Перечислим закрытые методы обработчики:
· engine_ServerStarted – обработка события запуска сервера.
· engine_ServerStopped – обработка события остановки сервера. Происходит очистка всех визуальных списков на окнах приложения.
· engine_ClientConnected – обработка события подключения нового клиента. В этом методе происходит добавление клиента в список.
· engine_PluginsLoaded – обработка события окончания загрузки плагинов сервером. В данном методе происходит добавление информации о доступных плагинах в список соответствующего окна.
· engine_ClientDisconnected – обработка события обнаружения отключения клиента. Происходит удаление данного клиента из списка.
Так же в данном классе определен закрытый метод mainFormToolBar_ButtonClick, реализующий обработку нажатия на кнопку главного окна приложения и соответствующие действия.
Ø MainForm
clip_image004
Рисунок 2. Главное окно приложения
Этот класс представляет собой главную форму приложения, представляющую собой панель, предоставляющую пользователю возможность запускать сервер, открывать другие окна приложения, сворачивать его и закрывать. Событие нажатие на любую из кнопок переадресовывается UIEngine в функцию mainFormToolBar_ButtonClick с соответствующим аргументом – классом нажатой кнопки.
Так же этот класс содержит в себе объект класса NotifyIcon, отвечающего за отображение значка в системном лотке. Если сервер не запущен, то значок белый, а если запущен – зеленый. По двойному щелчку по значку, все окна приложения появляются или скрываются, в зависимости от текущего состояния.
clip_image006
Рисунок 3. Значок сервера в системном лотке (сервер не запущен)

clip_image008
Рисунок 4. Значок сервера в системном лотке (сервер запущен)
Ø ClientsForm
Класс, отвечающий за форму, отображающую текущих подключенных пользователей. При подключении нового пользователя, он добавляется в список, отображающий название сервиса, обслуживающего пользователя и некоторое описание, предоставляемое сервисом (например, IP адрес для Wi-Fi/LAN сервиса).
Все пространство данного окна занимает список clientsListView, имеющий модификатор internal, то есть доступный для изменения внутри сборки (Assembly). Это необходимо, так как добавление и удаление клиентов в список происходит в классе UIEngine.
clip_image010
Рисунок 5. Окно списка подключенных клиентов (ClientsForm)
Ø PluginsForm
Класс, отвечающий за отображению списка доступных плагинов, который обновляется при старте сервера. Большую часть пространства данного окна занимает список pluginsListView, имеющий модификатор internal, то есть доступный для изменения внутри сборки (Assembly). Это необходимо, так как добавление и удаление плагинов в список происходит в классе UIEngine. В этом списке находится название плагина, его уникальный идентификатор, а так же список команд.
Так же в окне расположены два текстовых поля, отображающих информацию о назначении выбранного в списке плагина и информацию от разработчиков.
clip_image012
Рисунок 6. Окно списка загруженных плагинов (PluginsForm)
Ø HelpForm
Окно с логотипом приложения и упоминанием разработчиков. Никакой специальной функциональности и не несет.
clip_image014

Рисунок 7. Окно информации о разработчиков (HelpForm)
Ø Engine
Класс, являющийся "двигателем" приложения, обеспечивающий всю логику работы, загрузку модулей. Он связан с UIEngine событиями: запуска и остановки сервера, подключения и отключения клиентов, события завершения загрузки плагинов. Список событий:
· ServerStarted – событие, оповещающее, что запуск сервера завершился;
· ServerStoped – событие, оповещающее, что остановка сервера завершилась;
· PluginsLoaded – событие, оповещающее, что загрузка плагинов сервером завершена;
· ClientConnected – событие, оповещающее о подключении клиента;
· ClientDisconnected – событие, оповещающее об отключении клиента;
Следует сказать, что данный класс имеет поле Plugins, типа RPCMPluginHolder[] (массив), предоставляющее другим классам возможность получать информацию о загруженных плагинах.
Еще одной особенностью данного класса является то, что при старте сервера запускается поток, который каждые 5 секунд отправляет сообщение типа Test всем подключенным клиентам, отслеживая при этом исключение типа ConnectionClosedException из rpcmsdk.dll, получая которое, вызывает событие ClientDisconnected и удаляет клиента из списка клиентов (внтуреннего).
Ø ClientListViewItem
Класс, хранящий в себе указатель на объект, описывающий клиента, чтобы можно было при отключении данного клиента, найти и удалить его в списке
Ø RPCMPluginHolder – класс, являющийся "оберткой" класса типа RPCMPlugin, упрощая работу с данным классом. Значимого применения в данной реализации не имеет, но, в последствии, должен будет реализовывать логическую обработку данных, выполняя роль прослойки между сервером и плагином.

2 Библиотека rpcmsdk.dll

clip_image016
Рисунок 8. Диаграмма связи классов библиотеки rpcmsdk
Данная библиотека является необходимой и разделяемой между основным приложением, сервисами и плагинами. Она так же является необходимой при разработке дополнительных модулей. Рассмотрим, какие классы и интерфейсы в нее входят.
Абстрактные классы:
Ø RPCMPlugin
Интерфейс, описывающий набор методов, которые должен иметь плагин.
Ø RPCMNetworkService
Абстрактный класс, описывающий набор методов, которые должен иметь сервис, а также событие ClientConnected, возникающее в случае подключения нового клиента и передающее обработчику реализацию абстрактного класса Client.
Ø Client
Абстрактный класс, описывающий набор методов, которые должен иметь объект, создаваемый сервисом при подключении нового клиента, а также событие DataBytesReceived типа DataBytesReceivedHandler, оповещающее о получении данных от данного клиента.
Классы:
Ø RPCMData
Класс, являющейся переносчиком логической информации от плагина к сервису, содержит некоторую, необходимую для общения клиента и сервера, информацию, например, уникальный идентификатор плагина.
Ø Logger
Разделяемый класс, написанный, для унификации вывода отладочных сообщений и записи в файл отладочной информации.
Ø RPCMArrayConverter
В рамках поставленной задачи не редко приходится конвертировать массивы типа char[] в byte[] и наоборот, для этой цели был написан данный класс.
Ø NetworkDataParser
При разработке системы была принята концепция независимости среды передачи данных от логического наполнения этих данных. Данный класс является преобразователем объекта, хранящего некоторую логическую информацию о команде клиентскому приложению в массив байт, который должен быть передан через среду передачи данных (с помощью сервиса) и наоборот, преобразование массива байт, полученного от клиентского приложения в объект логических данных. Это, так же, позволяет изменять формат передачи данных, без изменений в других частях кода. К примеру, сейчас реализован фиксированный формат данных, приведенный на рисунке ниже. Планируется переход от данного формата к передаче данных в XML. Для этого необходимо будет изменить только данный класс.
Ø ConnectionClosedException
Класс исключения, которое должен посылать сервис при отключении клиента и невозможности послать ему сообщение.
Так же в состав библиотеки входит перечисление MessageTypes, в котором содержатся типы возможных посылаемых сообщений и тип делегата DataBytesReceivedHandler.

3 Формат передачи данных и типы сообщений

В данном разделе рассмотрим более подробно реализованный на данный момент формат сообщения, а также типы сообщений, которыми обмениваются клиент и сервер.
clip_image018
Рисунок 9. Формат сообщения
На рисунке слева указано имя поля, справа длина в байтах.
Ø GUID – 32 байта, уникальный идентификатора плагина, которому посылается сообщение от клиента или от которого было послано сообщение клиенту. Данное поле может также не использоваться в некоторых случаях;
Ø Message Type – 2 байта, тип сообщения. Перечислим все типы посылаемых сообщений, реализованные на данный момент:
· Test – тип сообщения для проверки на доступность клиента. Клиент может отсылать или не отсылать ответное сообщение, но если отсылает обратное сообщение, то только типа Test
· PluginDescriptionRequired – запрос описания всех плагинов (сообщение от клиента). В данном сообщении поле GUID игнорируется
· PluginDescription – содержит информацию о плагине следующего формата. GUID – идентификатор, а в поле Data идет символьная строка (ASCII и латиница) вида "Имя – разделитель – Описание – разделитель – Список команд через разделитель". На момент текущей реализации разделителем является символ '#'. В дальнейшем планируется унифицировать разбор сообщений данного типа, вынеся процедуру разбора в rpcmsdk.dll, так же планируется сделать поддержку Unicode.
· Command – содержит команду, клиентом посланную плагину. Поле GUID содержит идентификатор плагина. В данной реализации сравнение GUID плагина возложено сами на плагины, чтобы дать возможность писать системные плагины, такие как, например, NetworkDebugPlugin – отображающий все пришедшиесообщения.
· PluginResultInfoText – возвращает некоторую текстовую информацию от плагина клиенту (как, например, WinampControl Plugin, см. ниже). В дальнейшем планируется реализовать другие типы возвращаемой информации, например графические изображения.
Ø Length – 4 байта – указание размера поля Data, для избегания ошибок возврата неверного размера;
Ø Data - … - поле для посылаемой информации, зависящее от типа сообщения.

Комментариев нет:

Отправить комментарий