Искусство программирования для Unix
Шрифт:
Значительной частью того, что поддерживают программисты на С и С++, является специальный код для операций маршалинга и демаршалинга, даже если выбранная форма представления для сохранения и восстановления также проста как дамп бинарной структуры (распространенная методика в не Unix-средах). Современные языки, такие как Python и Java, имеют встроенные функции демаршалинга и маршалинга, которые применимы к любому объекту или потоку байтов, представляющему объект, и в значительной степени сокращают трудозатраты.
Однако эти простые методы часто неудовлетворительны в силу различных причин, включая упомянутые выше проблемы
Способность к взаимодействию, прозрачность, расширяемость и экономичность хранения или транзакций — важнейшие темы в проектировании форматов файлов и прикладных протоколов. Способность к взаимодействию и прозрачность требуют, чтобы при проектировании таких конструкций основное внимание было уделено четким формам представления данных, а не удобству реализации или максимальной производительности. Расширяемость также благоприятствует текстовым протоколам, так как двоичные протоколы часто труднее расширять или четко разделять на подмножества. Экономичность транзакций иногда заставляет двигаться в противоположном направлении, однако следует понимать, что выдвижение данного признака на первый план является некоторой формой преждевременной оптимизации. Более дальновидным будет все же противостоять ей.
Наконец, необходимо отметить отличие между форматами файлов данных и конфигурационных файлов, которые часто используются для установки параметров запуска Unix-программ. Самое основное отличие заключается в том, что (за редкими исключениями, такими как конфигурационный интерфейс редактора GNU Emacs) программы обычно не изменяют свои конфигурационные файлы — информационный поток является односторонним (от файла, считываемого при запуске, к настройкам приложения). С другой стороны, форматы файлов данных связывают свойства с именованными ресурсами, и такие файлы считываются и записываются соответствующими приложениями. Конфигурационные файлы, как правило,
редактируются вручную и имеют небольшие размеры, тогда как файлы данных генерируются программами и могут достигать произвольных размеров.
Исторически Unix обладает связанными, но различными наборами соглашений для данных двух видов представления. Соглашения для конфигурационных файлов рассматриваются в главе 10; в данной главе описываются только соглашения для файлов данных.
5.1. Важность текстовой формы представления
Каналы и сокеты передают двоичные данные так же, как текст. Однако есть важные причины, для того чтобы примеры, рассматриваемые в главе 7, были текстовыми: причины, связанные с рекомендацией Дуга Макилроя, приведенной в главе 1. Текстовые потоки являются ценным универсальным форматом, поскольку они просты для чтения, записи и редактирования
Кроме того, сами ограничения текстовых потоков способствуют усилению инкапсуляции. Препятствуя сложным формам представления с богатой, плотно закодированной структурой, текстовые потоки также препятствуют созданию программ, которые смешивают внутренние компоненты друг друга. Текстовые потоки также способствуют усилению инкапсуляции. Эта проблема рассматривается в главе 7 при обсуждении технологии RPC.
Если программист испытывает острое желание разработать сложный двоичный формат файла или сложный двоичный прикладной протокол, как правило, мудрым решением будет приостановить работу до тех пор, пока это желание не пройдет. Если основной целью такой разработки является производительность, то внедрение сжатия текстового потока на каком-либо уровне выше или ниже данного протокола прикладного уровня предоставит аккуратную и, вероятно, более производительную конструкцию, чем двоичный протокол (текст хорошо и быстро сжимается).
Плохим примером двоичных форматов в истории Unix был способ аппаратно-независимого чтения программой troff двоичного файла (предположительно в целях повышения скорости), содержащего информацию устройства. В первоначальной реализации данный двоичный файл генерировался из текстового описания способом, отчасти не пригодным для переноса на другие платформы. Столкнувшись с необходимостью быстро перенести ditroff на новую машину, я вместо того, чтобы переделывать двоичный материал, вырезал его и просто заставил ditroff читать текстовый файл. Тщательно созданный код чтения файла сделал потерю скорости незначительной.
Генри Спенсер.
Проектирование текстового протокола часто защищает систему в будущем, поскольку диапазоны в числовых полях не подразумеваются самим форматом. В двоичных форматах обычно определяется количество битов, выделенных для данного значения, и расширение таких форматов является трудной задачей. Например, протокол IPv4 допускает использование только 32-битового адреса. Для того чтобы увеличить размер до 128 бит (как это сделано в протоколе IPv6), требуется значительная реконструкция37. Напротив, если требуется ввести большее значение в текстовый формат, то его необходимо просто записать. Возможно, что какая-либо программа не способна принимать значения в данном диапазоне, однако, программу обычно проще модифицировать, чем изменять все данные, хранящиеся в этом формате.
Если планируется манипулировать достаточно большими блоками данных, применение двоичного протокола можно считать оправданным, когда разработчик действительно заботится о наибольшей плотности записи имеющегося носителя, или когда существуют жесткие ограничения времени или инструкций, необходимых для интерпретации данных в структуру ядра. Форматы для больших изображений и мультимедиа данных в некоторых случаях являются примерами первого случая, а сетевые протоколы с жесткими ограничениями задержки — примером второго.