Наши партнеры

UnixForum





Библиотека сайта rus-linux.net

Проект GPSD

Глава 7 из книги "Архитектура приложений с открытым исходным кодом", том 2.
Оригинал: GPSD, глава из книги "The Architecture of Open Source Applications" том 2
Автор: Eric Raymond
Перевод: Н.Ромоданов

7.4. Поток данных

Теперь мы рассмотрим архитектуру GPSD с точки зрения потока данных. В режиме нормальной работы gpsd представляет собой цикл, ожидающий входных данных от одного из следующих источников:

  1. Набора клиентов, передающих запросы через порт TCP/IP.
  2. Набора навигационных датчиков, подключенных через последовательные устройства или устройства USB.
  3. Специального управляющего сокета, используемого скриптами горячего подключения и некоторыми конфигурационными инструментальными средствами.
  4. Некоторого количества серверов, периодически выдающих корректирующие сообщения для GPS (DGPS и NTRIP). Эти сообщения будут обрабатываться точно также, как если бы они поступали от навигационных датчиков.

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

Когда клиент выдает запрос о том, что наступило время, слой мультиплексора открывает навигационные датчики в своем списке и начинает принимать от них данные (добавляя дескрипторы их файлов в набор в вызове main). В остальных случаях все устройства GPS закрыты (но остаются в списке) и демон находится в покое. Для устройств, которые прекратили отправку данных, в списке устройств устанавливается таймаут.

Рис.7.2: Поток данных

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

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

Затем основная библиотека перенаправляет пакет в драйвер, связанный с этим типом пакетов. Работа драйвера состоит в получении данных из пакета и помещения их в структуру, созданную в рамках сессии для конкретного устройства, а также установке некоторых битов состояния, сообщающих слою мультиплексора о том, какие данные он получил.

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

Основным экспортным механизмом является «сокет»; он создает объект сообщения в формате JSON и отправляет его всем клиентам, наблюдающим за устройством. Есть еще экспортный механизм с совместно используемой памятью, куда копируются данные вместо того, чтобы копировать их в совместно используемую память сегмента. В любом из этих случаев, предполагается, что клиентская библиотека распакует данные в структуру в памяти клиентской программы. Также доступен третий экспортный механизм, который сообщает о новом местоположении через шину DBUS.

Код GPSD распределен по горизонтали так же тщательно, как и по вертикали. Анализатор пакетов не знает и не должен знать ничего о том, чем нагружен пакет, и не должен беспокоиться о том, является ли его источником порт USB, устройство RS232, радиоканал Bluetooth, псевдо-терминал tty, соединение с сокетом TCP или поток пакетов UDP. В драйверах известно, чем загружен пакет, но ничего не известно о внутренних особенностях анализа пакетов и о экспортных механизмах. Экспортные механизмы рассматриваются только как сессионные структуры данных, обновляемые драйверами.

Такое разделение функций очень хорошо служит проекту GPSD. Например, когда в начале 2010 года мы получили запрос адаптировать код так, чтобы он для бортовой навигационной системы робота - подводной лодки принимал данные от датчика, поступающие в виде пакетов UDP, это удалось легко сделать с помощью нескольких строк кода без нарушения последующих этапов конвейера обработки данных.

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

7.5. Защищая архитектуру

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

На момент написания статьи мы обеспокоены тем, что, возможно, некоторую информацию о типе источника входных данных (USB, RS232, pty, Bluetooth, TCP, UDP) потребуется передавать в слой мультиплексора для того, чтобы ему сообщить, должны ли, например, в неопознанное устройство посылаться строки, позволяющие опознать устройство. Такие строки иногда необходимы для того, чтобы «разбудить» датчики RS232C, однако есть веские причины не отправлять их на любые другие устройства, где они не нужны. Многие устройства GPS и другие датчики создавались с малым бюджетом и в спешке; некоторые из них можно ввести в состояние ступора, если посылать им неожиданные управляющие строки.

По аналогичной причине в демоне есть параметр -b, который запрещает демону изменять скорость обмена данными во время цикла анализа, выполняемого анализатором пакетов. Некоторые плохо сделанные устройства Bluetooth справляются с такими ситуациями настолько плохо, что для того, чтобы их вновь заставить работать, их надо перезапустить при помощи отключения питания; в экстремальном случае пользователю для того, чтобы сбросить блокировку датчику, потребовалось в действительности отпаять батарейку резервного питания!

Оба этих случая являются необходимыми исключениями из общих правил разработки проекта. Однако, гораздо более обычны случаи, когда такие исключения ведут к плохим ситуациям. Например, у нас были некоторые патчи, предназначенные для того, чтобы служба времени PPS работала лучше, которые нарушали деление на вертикальные слои, что сделало невозможным PPS правильно работать с более чем с одним драйвером, для помощи которым патчи и были предназначены. Мы отказались от них и использовали более сложные устройства, которым не требовались улучшения.

Однажды несколько лет назад нас попросили о поддержке устройства GPS со странной особенностью, состоящей в том, что контрольные суммы в их пакетах NMEA могут быть неправильными в тех случаях, когда устройство не смогло определить местоположение. Для поддержки этого устройства, мы должны были бы либо (а) отказаться от проверки контрольных сумм для любых входящих данных, которые были похожи на пакеты NMEA, рискуя тем, что анализатор пакетов мог передавать мусор в драйвер NMEA, либо (б) добавить параметр командной строки, в котором принудительно указывается тип датчика.

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

Одной из самых важных обязанностей ведущего архитектора проекта является защита архитектуры от разумных «исправлений», который разрушают проект и будут причиной проблем его работы или сильной головной боли при его обслуживании в будущем. Аргументы, касающиеся этого, могут быть довольно горячими, особенно когда конфликт, связанный с защитой архитектуры, касается какой-либо функции, которая, по мнению разработчика или пользователя, считается незаменимой. Но этакие аргументы необходимы, поскольку самый простой вариант часто оказывается неправильным в более долгосрочной перспективе.


7.6. Нет конфигурирования - нет суеты