Главная страница
Навигация по странице:

  • Концепции программирования в Linux

  • Файлы и файловая система

  • Каталоги и ссылки

  • Символьные ссылки

  • Специальные файлы

  • Системное программирование Линукс. Linux. Системное программирование. Вступление


    Скачать 0.65 Mb.
    НазваниеLinux. Системное программирование. Вступление
    АнкорСистемное программирование Линукс
    Дата23.01.2023
    Размер0.65 Mb.
    Формат файлаpdf
    Имя файлаLinuxSystemProgramming.pdf
    ТипКраткое содержание
    #900372
    страница5 из 14
    1   2   3   4   5   6   7   8   9   ...   14
    37
    интерфейсов Linux, абстрагируясь от проблем совместимости с многочисленными другими UNIX­подобными системами и не думая о соответствии всем стандартам.
    Мы будем говорить только о Linux, поэтому можем позволить себе подробно оста­
    новиться на ультрасовременных интерфейсах этой операционной системы, которые, несомненно, останутся востребованными и действующими в обозримом будущем.
    В основу книги положены глубокие знания Linux, информация о реализации и по­
    ведении таких компонентов, как ядро и gcc
    . Эту работу можно считать повествова­
    нием разработчика­ветерана, полным проверенных методов и советов по оптими­
    зации.
    Концепции программирования в Linux
    В этом разделе вы найдете краткий обзор сервисов, предоставляемых в системе
    Linux. Все UNIX­подобные системы, включая Linux, предлагают общий набор аб­
    стракций и интерфейсов. На самом деле в этой взаимосовместимости и заключает­
    ся суть UNIX. Такие абстракции, как файл и процесс, интерфейсы для управления конвейерами и сокетами и т. д., являются главной составляющей систем UNIX.
    Этот обзор предполагает, что вы знакомы с системой Linux. Имеется в виду, что вы умеете обращаться с командной оболочкой, использовать базовые команды и ком­
    пилировать простую программу на C. Это не обзор Linux или системы для програм­
    мирования в ней, а рассказ об основах системного программирования Linux.
    Файлы и файловая система
    Файл — это самая простая и базовая абстракция в Linux. Linux придерживается философии «все есть файл», пусть и не так строго, как некоторые другие систе­
    мы — достаточно вспомнить Plan 9 1
    . Следовательно, многочисленные взаимодей­
    ствия представляют собой считывание из файлов и запись в них, даже если объект, с которым вы имеете дело, совсем не похож на «традиционный» файл.
    Вообще, чтобы получить доступ к файлу, его сначала нужно открыть. Файлы можно открывать для чтения, записи или того и другого сразу. На открытый файл указывает уникальный дескриптор, отображающий метаданные, ассоциированные с открытым файлом, обратно на сам этот файл. В ядре Linux такой дескриптор управляется целым числом (в системе типов C целому числу соответствует тип int
    ). Эта сущность, называемая файловым дескриптором, сокращенно обозначает­
    ся fd. Дескрипторы файлов совместно используются в системе и пользовательском пространстве. Пользовательские программы применяют их непосредственно для доступа к файлам. Значительная часть системного программирования в Linux сводится к открытию файлов, манипуляциям с ними, закрытию файлов и исполь­
    зованию файловых дескрипторов иными способами.
    1
    Plan 9 — это операционная система, разработанная в BellLabs и часто характеризующая­
    ся как наследница UNIX. В ней воплощено несколько инновационных идей, и она четко придерживается философии «все есть файл».
    Концепции программирования в Linux

    38
    Обычные файлы
    Сущности, которые большинству из нас известны под названием «файлы», в Linux именуются обычными файлами. Обычный файл содержит байты данных, органи­
    зованные в виде линейного массива, который называется потоком байтов. В Linux для файла не задается никаких других видов упорядочения или форматирования.
    Байты могут иметь любые значения и быть организованы внутри файла любы­
    ми способами. На системном уровне Linux не регламентирует для файлов ни­
    какой структуры, кроме организации в виде потока байтов. В некоторых опера­
    ционных системах, например VMS, используются высокоструктурированные файлы, в которых применяются так называемые записи. В Linux такие записи отсутствуют.
    Любые байты внутри файла могут использоваться для считывания или запи­
    си. Эти операции всегда начинаются с указанного байта, который можно назвать местоположением в файле. Это местоположение называется файловой позицией или смещением файла. Файловая позиция — это важнейший элемент метаданных, который ядро ассоциирует с каждым открытием файла. Когда файл открывается впервые, его файловая позиция равна нулю. Обычно по мере того, как байты из файла считываются либо в него записывается информация (байт за байтом), значение файловой позиции увеличивается. Файловую позицию можно также вручную устанавливать в определенное значение, причем оно может находиться даже за пределами (за последним байтом) конкретного файла. Когда файловая позиция находится за пределами файла, промежуточные байты будут заполнять­
    ся нулями. Вполне возможно воспользоваться этим способом и задать файловую позицию дальше конца файла, однако вы никак не сможете установить эту пози­
    цию перед началом файла. Правда, такая практика кажется бессмысленной и дей­
    ствительно она почти не применяется. Файловая позиция начинается с нуля; она не может иметь отрицательное значение. При записи в байт в середине файла значение, которое ранее находилось по этому смещению, заменяется новым, по­
    этому вы не сможете расширить файл, записывая информацию в его середину.
    Как правило, запись в файл происходит в его конце. Максимальное значение файловой позиции ограничено только размером типа C, используемого для хра­
    нения файла. В современных системах Linux максимальное значение этого пара­
    метра равно 64 бит.
    Размер файла измеряется в байтах и называется его длиной. Можно сказать, что длина — это просто количество байтов в линейном массиве, составляющем файл.
    Длину файла можно изменить с помощью операции, которая называется усечени-
    ем. Файл можно укоротить, уменьшив его размер по сравнению с исходным. В ре­
    зультате будут удалены байты, расположенные в конце файла. Термин «усечение» немного неудачный, поскольку им обозначается и удлинение файла, то есть уве­
    личение его размера по сравнению с исходным. В таком случае новые байты (до­
    бавляемые в конце файла) заполняются нулями. Файл может быть пуст (иметь нулевую длину) и, соответственно, не содержать ни одного валидного байта. Мак­
    симальная длина файла, как и файловая позиция, ограничена лишь размерами тех типов C, которые применяются ядром Linux для управления файлами. Однако
    Глава 1. Введение и основополагающие концепции

    39
    в конкретных файловых системах могут действовать собственные ограничения, из­за которых потолок длины файла существенно снижается.
    Отдельно взятый файл можно одновременно открыть несколько раз как в ином, так и в том же самом процессе. Каждому открытому экземпляру файла присваива­
    ется уникальный дескриптор. С другой стороны, процессы могут совместно ис­
    пользовать свои файловые дескрипторы, один дескриптор может применяться в не­
    скольких процессах. Ядро не накладывает никаких ограничений на параллельный доступ к файлу. Множественные процессы вполне могут одновременно считывать информацию из файла и записывать туда новые данные. Результаты такой парал­
    лельной работы зависят от упорядочения отдельных операций и, в принципе, непредсказуемы. Программы пользовательского пространства обычно должны взаимно координироваться, чтобы обеспечить правильную синхронизацию парал­
    лельных обращений к файлам.
    Хотя доступ к файлам обычно осуществляется по их именам, непосредственная связь файла с его названием отсутствует. В действительности ссылка на файл вы­
    полняется по индексному дескриптору
    1
    . Этому дескриптору присваивается цело­
    численное значение, уникальное для файловой системы (но не обязательно уни­
    кальное во всей системе в целом). Данное значение называется номером индексного
    дескриптора. В индексном дескрипторе сохраняются метаданные, ассоциированные с файлом, например отметка о времени его последнего изменения, владелец файла, тип, длина и местоположение данных файла, но имя файла там не сохраняется!
    Индексный дескриптор одновременно является и физическим объектом, располо­
    женным на диске в UNIX­подобной файловой системе, и концептуальной сущностью, представленной как структура данных в ядре Linux.
    Каталоги и ссылки
    Обращение к файлам по их индексным дескрипторам — довольно трудоемкий процесс (а также потенциальная брешь в системе безопасности), поэтому из поль­
    зовательского пространства файлы обычно вызываются по имени, а не по индексно­
    му дескриптору. Для предоставления имен, по которым можно обращаться к фай­
    лам, используются каталоги. Каталог представляет собой отображение понятных человеку имен в номера индексных дескрипторов. Пара, состоящая из имени и ин­
    дексного дескриптора, называется ссылкой. Физическая форма этого отображения, присутствующая на диске, например простая таблица или хеш, реализуется и управ­
    ляется кодом ядра, поддерживающим конкретную файловую систему. В принципе, каталог ничем не отличается от обычного файла, за исключением того, что в нем содержатся лишь отображения имен в индексные дескрипторы. Ядро непосред­
    ственно пользуется этими отображениями для разрешения имен в индексные дес­
    крипторы.
    Когда из пользовательского пространства приходит запрос на открытие фай­
    ла с указанным именем, ядро открывает каталог, в котором содержится файл с таким названием, и ищет данное имя. По имени файла ядро получает номер его
    1
    См.: http://ru.wikipedia.org/wiki/Inode. — Примеч. пер.
    Концепции программирования в Linux

    40
    индексного дескриптора. По этому номеру находится сам индексный дескриптор.
    Индексный дескриптор содержит метаданные, ассоциированные с файлом, в част­
    ности информацию о том, в каком именно фрагменте диска записаны данные этого файла.
    Сначала на диске присутствует лишь один корневой каталог. К нему обычно ведет путь
    /
    . Однако, как известно, в любой системе, как правило, множество ката­
    логов. Как ядро узнает, в каком именно нужно искать файл с заданным именем?
    Выше мы говорили о том, что каталоги во многом похожи на обычные файлы.
    Действительно, с ними даже ассоциированы свои индексные дескрипторы, поэто­
    му ссылки внутри каталогов могут указывать на индексные дескрипторы, находя­
    щиеся в других каталогах. Это означает, что одни каталоги можно вкладывать в дру­
    гие, образуя иерархические структуры, что, в свою очередь, позволяет использовать
    полные пути к элементам, знакомые каждому пользователю UNIX, например
    /home/blackbeard/concorde.png
    Когда мы запрашиваем у ядра открытие подобного пути к файлу, оно обходит все записи каталогов, указанные в пути к элементу. Так удается найти индексный дескриптор следующей записи. В предыдущем примере ядро начинает работу с /, получает индексный дескриптор home, идет туда, получает индексный дескриптор blackbeard, идет туда и, наконец, получает индексный дескриптор concorde.png. Эта операция называется разрешением каталога или разрешением пути к элементу.
    Кроме того, в ядре Linux используется кэш, называемый кэшем каталогов. В кэше каталогов сохраняются результаты разрешения каталогов, впоследствии обеспе­
    чивающие более быстрый поиск с учетом временной локальности
    1
    Если имя пути начинается с корневого каталога, говорят, что путь полностью
    уточнен. Его называют абсолютным путем к элементу. Некоторые имена путей уточнены не полностью, а указываются относительно какого­то другого каталога
    (например, todo/plunder). Такие пути называются относительными. Если ядру предоставляется относительный путь, то оно начинает разрешение пути с текуще-
    го рабочего каталога. Отсюда ядро ищет путь к каталогу todo. В каталоге todo ядро получает индексный дескриптор plunder
    . В результате комбинации относительно­
    го пути к элементу и пути к текущему рабочему каталогу получается полностью уточненный путь.
    Хотя каталоги и воспринимаются как обычные файлы, ядро не позволяет их открывать и производить с ними те же манипуляции, что и с обычными файлами.
    Для работы с каталогами используется специальный набор системных вызовов.
    Эти системные вызовы предназначаются для добавления и удаления ссылок — в принципе, на этом перечень разумных операций с каталогами заканчивается. Если бы можно было манипулировать каталогами прямо из пользовательского простран­
    ства, без посредничества ядра, то единственной простой ошибки хватило бы для повреждения всей файловой системы.
    1
    Временная локальность — это высокая вероятность обращения к конкретному ресурсу после другой, более ранней операции доступа к нему же. Временная локальность харак­
    терна для многих ресурсов компьютера.
    Глава 1. Введение и основополагающие концепции

    41
    Жесткие ссылки
    С учетом всего вышесказанного ничто вроде бы не препятствует разрешению мно­
    жества имен в один и тот же индексный дескриптор. Действительно, это допуска­
    ется. Когда множественные ссылки отображают различные имена на один и тот же индексный дескриптор, эти ссылки называются жесткими.
    Благодаря жестким ссылкам в файловых системах обеспечивается создание сложных структур, где множественные имена путей могут указывать на одни и те же данные. Эти жесткие ссылки могут находиться в одном каталоге, а также в двух и более различных каталогах. В любом случае ядро просто разрешает имя пути в вер­
    ный индексный дескриптор. Например, можно поставить жесткую ссылку на кон­
    кретный индексный дескриптор, ссылающийся на определенный фрагмент данных из двух мест —
    /home/bluebeard/treasure.txt и
    /home/blackbeard/to_steal.txt
    При удалении файла он отсоединяется от структуры каталогов. Для этого нуж­
    но просто удалить из каталога пару, в которой содержится имя файла и его индекс­
    ный дескриптор. Однако, поскольку в Linux поддерживаются жесткие ссылки, файловая система не может просто уничтожать индексный дескриптор и ассоци­
    ированные с ним данные при каждой операции удаления. Что, если на этот файл были проставлены и другие жесткие ссылки из файловой системы? Чтобы гаран­
    тировать, что файл не будет уничтожен, пока не исчезнут все указывающие на него жесткие ссылки, в каждом индексном дескрипторе содержится счетчик ссылок, отслеживающий количество ссылок в файловой системе, указывающих на этот дескриптор. Когда путь к элементу отсоединяется от файловой системы, значение этого счетчика уменьшается на 1. Лишь если значение счетчика ссылок достигает нуля, и индексный дескриптор, и ассоциированные с ним данные окончательно удаляются из файловой системы.
    Символьные ссылки
    Жесткие ссылки не могут связывать файловые системы, поскольку номер индекс­
    ного дескриптора не имеет смысла вне его собственной файловой системы. Чтобы ссылки могли соединять информацию из различных файловых систем, становясь при этом и более простыми, и менее прозрачными, в системах UNIX применяются так называемые символьные ссылки.
    Символьные ссылки похожи на обычные файлы. Такая ссылка имеет свой ин­
    дексный дескриптор и ассоциированный с ним фрагмент данных, содержащий полное имя пути к связанному файлу. Таким образом, символьные ссылки могут указывать куда угодно, в том числе на файлы и каталоги, расположенные в иных файловых системах, и даже на несуществующие файлы и каталоги. Символьная ссылка, указывающая на несуществующий файл, называется сломанной.
    C использованием символьных ссылок связано больше издержек, чем при ра­
    боте с жесткими ссылками, так как символьная ссылка, в сущности, требует разре­
    шения двух файлов: самой символьной ссылки и связанного с ней файла. При ис­
    пользовании жестких ссылок такие дополнительные затраты отсутствуют — нет разницы между обращениями к файлам, обладающим одной связью в файловой
    Концепции программирования в Linux

    42
    системе либо несколькими связями. Издержки при работе с символьными ссыл­
    ками минимальны, но тем не менее они воспринимаются отрицательно.
    Кроме того, символьные ссылки менее прозрачны, чем жесткие. Использование жестких ссылок — совершенно очевидный процесс. Более того, не так просто най­
    ти файл, на который проставлено несколько жестких ссылок! Для манипуляций же с символьными ссылками требуются специальные системные вызовы. Эта не­
    прозрачность зачастую воспринимается как положительный момент, так как в сим­
    вольной ссылке ее структура выражается открытым текстом. Символьные ссылки используются именно как инструменты быстрого доступа (ярлыки), а не как внутрисистемные ссылки.
    Специальные файлы
    Специальные файлы — это объекты ядра, представленные в виде файлов. С годами в системах UNIX накопилось множество типов поддерживаемых специальных файлов. В Linux поддерживается четыре типа таких файлов: файлы блочных устройств, файлы символьных устройств, именованные каналы
    1
    и доменные соке­
    ты UNIX. Специальные файлы обеспечивают возможности встраивания опреде­
    ленных абстракций в файловую систему и, таким образом, поддерживают парадиг­
    му «все есть файл». Для создания специального файла в Linux предоставляется специальный системный вызов.
    Доступ к устройствам в системах UNIX осуществляется через файлы устройств, которые выглядят и действуют как обычные файлы, расположенные в файловой системе. Файлы устройств можно открывать, считывать из них информацию и за­
    писывать ее в них. Из пользовательского пространства можно получать доступ к фай­
    лам устройств и манипулировать устройствами в системе (как физическими, так и виртуальными). Как правило, все устройства в UNIX подразделяются на две группы — символьные устройства и блочные устройства. Каждому типу устрой­
    ства соответствует свой специальный файл устройства.
    Доступ к символьному устройству осуществляется как к линейной последова­
    тельности байтов. Драйвер устройства ставит байты в очередь, один за другим, а про­
    грамма из пользовательского пространства считывает байты в порядке, в котором они были помещены в очередь. Типичным примером символьного устройства яв­
    ляется клавиатура. Если пользователь наберет на клавиатуре последовательность peg
    , то приложению потребуется считать из файла­устройства клавиатуры снача­
    ла p
    , потом e
    и, наконец, g
    — именно в таком порядке. Когда больше не остается символов, которые необходимо прочитать, устройство возвращает «конец файла»
    (EOF). Если какой­то символ будет пропущен или символы будут прочтены в не­
    правильном порядке, то операция получится фактически бессмысленной. Доступ к символьным устройствам происходит через файлы символьных устройств.
    1
    Именованный канал называется в оригинале named pipe, более точный перевод — имено­
    ванный конвейер. Тем не менее мы остановимся на варианте «именованный канал»
    (http://ru.wikipedia.org/wiki/Именованный_канал), как на более употребительном в рус­
    ском языке, а термин pipe будем далее переводить как «конвейер». — Примеч. пер.
    Глава 1. Введение и основополагающие концепции

    1   2   3   4   5   6   7   8   9   ...   14


    написать администратору сайта