Домашняя телеметрия
Система домашней телеметрии
Сбор и анализ информации с датчиков
Главная › Описание › Серверная часть


X. Серверная часть.


Общие понятия об Internet-сервере.

Internet-сервер - постояно подключенный к сети Internet компьютер, предоставляющий другим компьютерам-клиентам разноообразные сервисы. Сервисами могут быть вычислительные и дисковые ресурсы, ведение баз данных, выполнение различных запросов и команд. Сервисы предоставляются с помощью постоянно находящихся в памяти компьютера программ - процессов. Эти процессы, как правило, не используют дисплей и клавиатуру - работают в фоновом режиме. В среде Windows их называют сервисами, в Linux - демонами. Internet-сервер в нормальном режиме работы работает полностью автоматически и не требует участия человека. Клиенты же наоборот, часто работают во взаимодействии с человеком, поэтому компьютер-клиент часто называют терминалом или ПЭВМ.

Web-сервер - процесс на Internet-сервере, предоставляющий возможность доступа к Internet-сайтам. В дальнейшем под названием сервер будем понимать Web-сервер. Internet-сайт (в дальнейшем просто сайт) - набор гипертестовых страниц, объединенных под общим именем - доменом. Основной особенностью Web-сервера являтся работа в режиме запрос-ответ, также называемом пакетном. В этом режиме сервер получает от клиента запрос, устанавливает с клиентом соединение, выполняет запрос, выдает ответ, закрывает соединение и "забывает" про запрос. В процессе выполнения запроса сервер может открывать файлы, устанавливать соединение с сервером БД и т.п., но после выполнения запроса все файлы и соединения будут закрыты. Такой подход обладает высокой универсальностью - на одном сервере может находится множество никак не связанных между собой сайтов. Но в тоже время увеличивает накладные расходы. Для каждого нового обмена данными нужно вновь проверять клиента, открывать БД и т.д.

Гипертекстовая страница, она же Internet-страница, она же HTML-страница - текст со специальной разметкой, т.н. тэгами. С помощью тэгов в обычный тест вставляются разнообразные объекты - ссылки, таблицы, изображения и т.п. Отображение Internet-страниц выполняет на стороне клиента специальная программа - браузер. По мере развития аппаратно-программных средств возможности по взаимодействию страницы с пользователем, т.н. интерактивность постоянно расширяется. Сначала это были просто ссылки, потом был добавлен JavaScript, потом AJAX, сейчас на основе AJAX активно развивается Comet.

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

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

Comet - общее название способов, с помощью которых можно оперативно информировать пользователя о событиях на сервере. Существует 3 основных способа:

  1. Периодический опрос сервера клиентом (polling).
    На JavaScript создается таймер, который с периодичностью в несколько секунд посылает AJAX запросы на сервер. Если событий нет, сервер отвечает условным сообщением "событий нет". Недостатком такого подхода является повышение нагрузки на сервер - если кто-то просто зашел на сайт (открыл страницу) и ничего не происходит, все равно серверу приходится постоянно обрабатывать запросы пока посетитель остается на странице . Если же увеличить период опроса, уменьшится оперативность, что в динамичных приложениях (например в чате) может раздражать.
  2. Длинный опрос сервера клиентом (long polling).
    Здесь также клиент посылает серверу запрос, но сервер не отвечает и не закрывает соединение сразу, а ждет пока появится событие, о котором нужно проинформировать клиента. Такой подход позволяет при редких событиях уменьшить нагрузку на сервер, а также уменьшить время отклика. Фактически как только произходит событие, клиент о нем сразу узнает. После передачи ответа сервер закрывает соединение. Клиент, получив ответ, отправляет новый запрос.
  3. Постоянное соединение.
    В настоящее время активно разрабатывается стандарт websocket, позволяющий создать полноценное постоянное соединение между сервером и браузером. Примеров его использования мало, поэтому ограничимся только этим напоминаем.
    Постоянное соединение также использовалось в ранных реализациях Comet, когда не было AJAX. Реализация не вполне стандартная, поэтому может не всегда работать. Используется тот факт, что браузеры как правило обрабатывают содержимое страницы сразу, не дожидаясь полной загрузки. Клиент создает невидимый фрейм, посылает запрос на сервер. Сервер не отвечает и не закрывает соединение, а при возникновении событий посылает блок с JavaScript-кодом, который сразу выполняется браузером и выполняет необходимые действия на основной странице. Для очистки от старых сообщений периодически фрейм перезагружается.

Организация системы на сервере.

В проекте Telemetry используется long polling для создания терминала и передачи команд от пользователя к ЦК напрямую, что требуется для отладки и настройки. Также используется AJAX для динамической перезагрузки графиков в статистике.

Недостатком МК AT90USB162 является очень маленький объем ОЗУ, поэтому организовать периодический опрос ЦК сервером не получится - данные могут теряться. Придется порт держать постоянно открытым. Кроме того, хочется отработать возможность наблюдения за работой ЦК одновренно с нескольких мест, а к порту возможен только монопольный доступ. Поэтому требуется постоянно работающая программа - демон.

Таким образом серверная часть системы состоит из 3-х частей:
  1. Постоянно работающий процесс - т.н. демон*.
    Выполняет получение данных от COM-порта, запись телеметрической информации в БД MySQL, связь по требованию со скриптом посредством т.н. сокета. Что получено из сокета, пишет в COM-порт и во все активные сокеты, включая тот, из которого прочитаны данные. Что получил из COM-порта пишет во все активные сокеты. Если получено TM-сообщение, то дополнительно разбирает его на части и записывает в БД. Т.к. Web сервер работает по принципу запрос-ответ, то чтобы получаемые между запросами данные не терялись, содержит буфер с нумерованными строками, который выдает весь при установлении соединения по сокету, в дальнейшем только новые строки.
  2. PHP cкрипт Backend.
    Устанавливает связь с демоном и выдает пользователю сообщения от демона.
  3. PHP cкрипт Frontend.
    Поддерживает пользовательский Web-интерфейс.

Для исключения несанкционированного доступа к консоли и статистическим данным применена авторизация пользователей с разделением на уровни доступа:

  1. Без авторизации.
    Только демо. Использование консоли как чата, просмотр специально сгенерированных демо-данных.
  2. Уровень 0.
    Генерация демо-данных.
  3. Уровень 1.
    Просмотр реальных статистических данных.
  4. Уровень 2.
    Управление ЦК через консоль.

Авторизация пользователей выполнена типовым способом через cookie. У пользователя запрашивается имя и пароль. На сервере в БД есть таблица. Строка таблицы содержит: имя пользователя, хеш пароля, идентификатор пользователя, уровень доступа пользователя. При авторизации в БД ищется пользователь с указанным именем. Если пользователь найден, проверяется хеш пароля. Если проверка прошла успешно, пользователю присваивается идентификатор, создаваемый случайным образом. Идентификатор записывается в БД на сервере и в cookie у пользователя. При следующих запросах пользователя в БД ищется идентификатор, полученный от пользователя. Если идентификатор найден, то по нему определяем имя и уровень доступа. Проверка авторизации выполняется в начале скрипта. Перед выполнением действия, требующего авторизации, проверяется уровень доступа пользователя.


Примечание*:
Последовательность создания демона.
Для создания любой программы на C под Linux, должны быть установлены пакеты GCC, библиотеки и заголовочные файлы. Создание демона состоит из 5-ти частей:
  1. Взаимодействие с сокетами.
    Тема хорошо освещена в Internete, поиск можно провести по ключевым словам "Основы socket API". Надо провести подготовительные операции: создать серверный сокет, превратить в неблокирующий, связать с интерфейсом (в моем случае localhost), перевести в режим ожидания. Войти в основной цикл: подготовка дискрипторов для select, ожидание в select, разбор событий.
    Также нужно обратить внимание на одну деталь - обязательно задать режим игнорирования сигнала SIGPIPE, функцией signal. Все программы в Linux обрабатывают сигналы, даже если их обработка в явном виде не задана. В обработке по-умолчанию большинство сигналов игнорируются, но часть их приводит к немедленному завершению программы. Сигнал SIGPIPE как раз из таких. Он возникает в тех случаях, когда программа пытается писать в канал связи, который разорван. Такая ситуация не редкость - например клиент открыл соединение и сразу же его закрыл. Событие "отключение по чтению 0 байт" еще не получено, а канал уже разорван.
  2. Взаимодействие с коммуникационными портами.
    Тоже хорошо освещена. Ключевые слова "termios", "Serial Programming HOWTO", есть документ на русском языке. Последовательность действий такая же: открытие порта, подготовка дискрипторов, ожидание, чтение. Неиспользуемые флаги и все управляющие символы можно занулить. Хорошо работает канонический режим, но в этом режиме не стоит использовать флаг IGNCR - читаться ничего не будет. Легко отслеживать подключение/отключение ЦК без перезапуска программы - отключение по чтению 0 байт, подключение - по таймауту в select и повторных попытках открыть порт. Не забыть про права - программу надо запускать под root или от имени пользователя, входящего в группу dialout.
    При отладке на виртуальной платформе Oracle VM VirtualBox, нужно учитывать и не боятся неприятного эффекта - с вероятностью 50% чтение данных из конечной точки ЦК и их получение в программе прекращается. Наиболее вероятно в этом виноваты дополнения ОС. На реальном сервере такого эффекта не наблюдается. Более подробно об этом было написано выше.
  3. Взаимодействие с MySQL.
    Все подробно с примерами расписано на mysql.ru. Если что-то не получается, то можно добавить вывод подробного описания ошибки с помощью функции mysql_error. Кратко опишем только последовательность компиляции.
    1. Для работы клиента нужно установить пакет libmysqlclient, для компиляции libmysqlclient-dev. При этом будут установлены заголовочные файлы в /usr/include/mysql и файлы библиотек в /usr/lib.
    2. Для компиляции программы нужно указать расположение заголовочных файлов опцией -I, расположение библиотек опцией -L и имена используемых библиотек опцией -l. Библиотека используется только одна mysqlclient. Получится, например такая командная строка:

          g++ test_mysql.c -o test_mysql -I/usr/include/mysql -L/usr/lib -lmysqlclient
         
      Если хочется использовать протокол со сжатием, можно добавить опцию -lz (библиотека zlib).
  4. Демонизация программы.
    Изначально демон можно писать и отлаживать как обычную консольную программу. Чтобы перевести программу в фоновый режим, надо при её запуске добавить к имени символ &, например "./tmdm&". В фоновом режиме все отладочные сообщения, выдаваемые с помощью printf, по прежнему выводятся на консоль. Перевод в интерактивный режим командой fg. Принудительное завершение - в интерактивном режиме нажать Ctrl-C. Приостановка Ctrl-Z, продолжение fg. Но в таком режиме работы программа связана с консолью, из которой она была запушена, и принудительно завершается при закрытии консоли.
    Чтобы программа при закрытии консоли не завершалась, нужно оформить её в виде демона. Демон представляет собой обычную консольную программу, но с "демонизацией" в начале. Все также подробно с примерами можно найти в Internet. Ключевые слова "Linux Daemon HOWTO".
    Основная последовательность: отделение (ответвление, fork) от родительского процесса, изменение файловой маски (umask), открытие журналов, создание уникального ID сессии (SID), изменение текущего рабочего каталога, закрытие стандартных файловых дескрипторов, переход к коду демона.
  5. Автозагрузка демона.
    Демона можно загрузить из консоли, после завершения сеанса демон продолжит работу. Но после перезагрузки его придется запускать снова. Возможные решения:
    1. Загружать через init.
      Процесс init специально предназначен для загрузки служб. Для загрузки нужно написать специальный скрипт и разместить его в каталоге /etc/rcN.d, где N - уровень загрузки. Наиболее правильное решение, позволяет задать дополнительные условия загрузки, но требует навыков в написании загрузочных скриптов.
    2. Загружать через файл /etc/rc.local.
      В файл можно сразу вписать любые shell-команды. Никакие условия и параметры не требуются.
    Решено было использовать второй способ. В файл /etc/rc.local перед строкой
    exit 0
    была вписана строка
    /usr/share/tmdm/tmdm