Книга: Разработка приложений в среде Linux. Второе издание
Сноски из книги
· #1Andrew Tanenbaum, Computer Networks, Prentice Hall, 1981, стр. 168.
· #2По этой причине некоторые люди называют GPL "вирусом". — Примеч. авт.
· #3Это справедливо для тех, кто привык к раскладке qwerty. Те, кто обучался на клавиатуре Дворака, используют множество макросов vi, которые делают его удобным в наборе.
· #4Несмотря на то что такое поведение выглядит неудобным, это важное средство, а не ошибка. Неразворачиваемые переменные критически важны при написании обобщенных суффиксных правил, которые создают подразумеваемые зависимости.
· #5Большинство версий make, включая версию GNU, распространяемую с Linux, определят бесконечный цикл и завершатся с выдачей соответствующего сообщения об ошибке.
· #6Большинство, но не все, поставщики услуг доступа в Internet назначают динамические IP-адреса, а не статические.
· #7Несмотря на имя, которое может ввести в заблуждение, этот системный вызов устанавливает имя узла, а не имя Internet-хоста машины.
· #8Сетевые информационные службы (Network Information Services — NIS) предоставляют для машин в сети механизм совместного использования информации, такой как пользовательские имена и пароли. Ранее они назывались "желтыми страницами" (Yellow Pages — YP). Имя домена NIS — часть этого механизма, который реализуется за пределами ядра системы с тем исключением, что доменное имя хранится в структуре utsname
.
К сожалению, ни одно из средств, описанных в этой главе, не может отследить ошибки в памяти, связанные с глобальными переменными; для этого нужна помощь компилятора. В первом издании этой книги рассматривался инструмент под названием Checker, который представлял собой модифицированную версию компилятора gcc
, однако он больше не поддерживается. К официальному компилятору gcc
добавлена новая технология под названием mudflap, которая описана в текущем руководстве по gcc
.
Для большей переносимости многие из средств mpr
анализа журнала используют gdb
для связывания адреса с соответствующим местом в исходном коде. Чтобы это работало, программа должна содержать отладочную информацию.
Большинство традиционных систем Unix передают ошибку шины (SIGBUS
) процессу, который пытается использовать невыровненные данные. Ядро Linux обрабатывает доступ к невыровненным данным так, чтобы процесс мог нормально продолжать работу, хотя за это приходится платить существенным снижением производительности.
Во всяком случае это справедливо для систем Linux/Intel и Linux/SPARC. Размер страницы зависит от базовой аппаратной архитектуры и в некоторых системах может составлять 16 Кбайт и больше.
· #13Разница между -fPIC
и -fpic
заключается в способе генерации независимого от расположения кода. В некоторых архитектурах с помощью -fpic
можно собрать только относительно небольшие совместно используемые библиотеки, тогда как в других эти флаги дают один и тот же эффект. Если только нет веских причин на обратное, лучше использовать -fPIC
вместо -fpic
, тогда все будет работать должным образом во всех архитектурах.
В случае удаления /etc/ld.so.cache
система может замедлиться. Для восстановления /etc/ld.so.cache
запустите ldconfig
.
Для многопоточных приложений библиотека хранит код ошибки там, где функция errno()
, которой известно, какой поток является текущим, может получить ее. Разные потоки могут содержать разные текущие коды возврата ошибок.
uid и gid обычно представляют собой положительные целые, но отрицательные целые тоже имеют определенное назначение. Применение -1 для идентификатора проблематично, однако многие системные вызовы, работающие с uid и gid, используют -1
в качестве признака, что модифицировать значение не нужно (см. пример этого в setregid()
далее в главе).
Процессы Linux также имеют четвертый uid и gid, используемые для файлового доступа. Они обсуждаются в следующем разделе этой главы.
· #18Большинство систем передают окружение в виде параметра main()
, но такой метод не включен в стандарт POSIX. Переменная environ
— это метод, утвержденный POSIX.
Детальную информацию о том, как родительские и дочерние открытые файлы соотносятся друг с другом, можно найти в главе 11.
· #20Группы процессов рассматриваются далее в этой главе
· #21В главе 15 описаны причины, по которым это может произойти.
· #22Это тот же формат, который использует команда env
для печати текущих значений переменных окружения, и аргумент envp
имеет тот же тип, что и глобальная переменная environ
.
Технически это указатель на завершающийся NULL
массив указателей на массивы символов, каждый из которых завершается символом ''
. Более подробно об это рассказано в [15].
Появление vfork()
было мотивировано старыми системами, которым необходимо было копировать всю память, используемую исходным процессом, как часть fork()
.Современные операционные системы используют копирование при записи, которое копирует области памяти только по необходимости, как это описано во многих источниках, посвященных операционным системам, в частности [40] и [2]. Это свойство делает fork()
почти таким же быстрым, как vfork()
, и намного более простым в использовании.
Это — существенное упрощение. В действительности kill()
посылает сигнал, а сигналы сами по себе достаточно сложная тема. См. полное описание того, что такое сигналы и как их применять, в главе 12.
Это нужно для того, чтобы управляющая заданиями оболочка могла перезапускать процессы, у которых изменился эффективный идентификатор пользователя. Более подробно об управлении заданиями рассказывается в главе 15.
· #27Одна из популярных ранее форм компьютерной памяти выглядела как набор маленьких железных колечек, расположенных на матрице, к каждому из которых подводились два проводка, служащих для установки и считывания магнитной полярности кольца. Эти кольца назывались ядрами (cores), а все вместе — ядерной памятью. Поэтому дамп ядра — это копия состояния системной памяти в определенный момент времени.
· #28В процессе работы system()
блокирует SIGCHILD
, что заставляет передавать этот сигнал программе непосредственно перед тем, как system()
вернет управление (но после того, как system()
вызовет wait()
для порожденного процесса), поэтому программы, которые используют обработчики сигналов, должны это учитывать и обрабатывать такие ложные сигналы осторожно. Функция system()
также игнорирует SIGINT
и SIGQUIT
, а это означает, что быстрые циклические повторные вызовы system()
может оказаться невозможно прервать ничем, кроме SIGSTOP
и SIGKILL
.
Хотя функция popen()
это делает просто, с ней связаны некоторые побочные эффекты, которые не сразу становятся очевидны. Она создает дочерний процесс, который может быть прерван перед тем, как будет вызвана pclose()
, что заставит функцию wait()
вернуть состояние процесса. Когда этот процесс завершится, он также сгенерирует SIGCHLD
, что может привести в замешательство упрощенно написанный обработчик сигналов.
Этот тип обработки часто приводит к взаимоблокировкам, при которых процесс А ожидает, пока процесс В выполнит какую-то работу, в то время как процесс В ожидает процесса А, в результате чего ничего не происходит.
· #31Если вам понадобится делать это, запустите дочерний процесс с помощью fork()
и exec()
, а потом воспользуйтесь poll()
для чтения и записи в дочерний процесс. Для этого предназначена программа под названием expect
.
Информацию о чтении и записи в поток stdio
можно найти в [15].
В главе 15 все это проясняется, поэтому, возможно, будет полезно сначала прочитать ее.
· #34Но, может быть, не сразу. Может существовать группа процессов, содержащая процессы, чьи родители относятся к другой группе в том же сеансе. Поскольку отношения "родительский-дочерний" между процессами образуют дерево, иногда может оказаться, что существует группа процессов, которая содержит только те процессы, чьим родителем является оболочка, и когда такая группа процессов завершается, другая становится висячей.
· #35Обсуждение станет более понятным после того, как вы прочитаете главы, посвященные сигналам (глава 12) и управлению заданиями (глава 15).
· #36В среде Linux файловая система /proc
включает информацию о каждом файле, открытом в системе в данный момент. Хотя это значит, что неименованные каналы могут быть найдены в файловой системе, все же они не имеют постоянных имен, потому что исчезают при завершении процесса, использующего их.
Не все блочные устройства представляют реальное оборудование. Более правильное описание блочных устройств — это нечто, на чем может располагаться файловая система; блочное устройство обратной связи (loopback block device) отображает на обычный файл логическое блочное устройство, что позволяет файлам содержать в себе целые файловые системы.
· #38Точнее говоря, они кэшируются и доступ к ним упорядочен.
· #39Это отличается от ряда систем, которые способны монтировать файловые системы как на символьных устройствах, так и на блочных.
· #40В Linux всегда используется термин inode для обоих типов информационных узлов, в то время, как другие варианты Unix резервируют термин inode только для дисковых узлов, а узлы в памяти называют vnode. Хотя такая терминология менее запутана, мы будем использовать термин inode для обоих типов узлов, чтобы сохранять соответствие стандартам Linux.
· #41Это режим, обычно используемый для каталога /tmp
.
readv()
, writev()
и mmap()
обсуждаются в главе 13; sendmsg()
и recvmsg()
упоминаются в главе 17.
Хотя такое разделение почти ясно, сокеты TCP поддерживают "внеполосные" данные, что несколько усложняет ситуацию. Такие данные выходят за пределы тем, рассматриваемых в этой книге. Их полное описание можно найти в [33].
· #44Почти независимую; см. описание исключений из этого правила в дискуссии о dup()
в конце этой главы.
Поскольку в большинстве систем SEEK_SET
определена как 0, часто можно увидеть использование lseek(fd, offset, 0)
вместо lseek(fd, offset, SEEK_SET)
. Это делает код непереносимым (или плохо читабельным), чем SEEK_SET
, но подобное часто встречается в старом коде.
Все же не всегда. Если процессы разделяют файловые дескрипторы (имеются в виду дескрипторы, полученные от одного вызова open()
),эти процессы разделяют одни и те же файловые структуры и одно и тоже текущее положение. Наиболее часто такое случается после вызова fork()
,как обсуждается в конце этой главы. Другая ситуация, когда такое может случиться — это если файловый дескриптор передается другому процессу через доменный сокет Unix, описанный в главе 17.
Она так называется потому, что это протоколируемая версия Second Extended File System (второй расширенной файловой системы), которая была наследницей Linux Extended File System, которая, в свою очередь, была спроектирована как более сложная файловая система, чем файловая система Minix — единственная, которую изначально поддерживалась в Linux.
· #48В действительности это хорошо работает и на файловой системе ext2. Эти две файловые системы очень похожи (можно даже смонтировать систему ext3 на ext2), и представленные программы работают на обеих. Фактически, если в исходных тексте заменить 3 на 2, программы будут функционировать точно так же.
· #49Хотя не гарантировано, что PATH_MAX
будет достаточно велик, но для большинства практических целей она подходит. Если вы имеете дело с патологическими случаями, то должны вызывать readlink()
последовательно, увеличивая буфер, до тех пор, пока readlink()
не вернет значение меньше чем bufsiz
.
В зависимости от операционной системы, файловые структуры также известны как позиции в таблице файлов или объекты открытых файлов.
· #51Файловый дескриптор в каждом процессе ссылается на одну и ту же файловую структуру.
· #52Эта терминология распространена в большей части литературы по стандартам, включая единую спецификацию Unix (Single Unix Specification).
· #53Это механизм, используемый для утилиты nohup
.
Необходимость в реентерабельных функциях не ограничивается обработчиками сигналов. Многопоточные приложения должны с большой осторожностью относиться к обеспечению реентерабельности и блокировкам.
· #55Вообще-то, не совсем так. Модель обработки сигналов ANSI/ISO С специфицирована немного иначе, чем мы ее представили. Однако она допускает сброс обработчика в значение SIG_DFL
перед доставкой сигнала, что делает функции signal()
в ASNI/ISO С ненадежными.
Спецификация POSIX Real Time Signal позволяет некоторые сигналам ставить в очередь, и для сигналов, работающих с ограниченными объемами данных, существенно изменяет эту модель. Сигналы реального времени обсуждаются ближе к концу этой главы.
· #57Это аналогично типу fd_set
, который используется системным вызовом select()
, описанным в главе 13.
Разница между быстрыми и медленными файлами та же, что и между быстрыми и медленными системными вызовами, и она обсуждается в главе 11.
· #59Имеются и другие отличия между этими вызовами; они касаются многопоточных программ, которые в настоящей книге не рассматриваются.
· #60В действительности она отправляет сигнал текущему потоку текущего процесса.
· #61Эти флаги определены в Single Unix Specification. Многие из них имеют имена, отличающиеся от описанных в тексте.
· #62Хотя ссылка на память, которая может быть заполнена, может работать в некоторых системах, это не является переносимым. Некоторые реализации malloc()
возвращают память операционной системе, что при обращении к возвращенной памяти вызывает ошибку сегментации; другие — перезаписывают части заполненной памяти служебной информацией.
Применение sigprocmask()
и pause()
для получения требуемого поведения может вызвать состояние состязаний, если сигнал, появление которого ожидается, поступит между этими двумя системными вызовами.
Более подробно о дампах памяти рассказывается в главе 10.
· #65Хотя пользователи могут посылать SIGCHLD
любым процессам, которыми они владеют, программы не обладают возможностью должным образом реагировать на непредвиденные сигналы.
В табл. 12.2 перечислены функции, которые могут отсутствовать в некоторых, а может, даже во всех системах Linux. Мы включаем все функции, которые POSIX специфицирует в качестве безопасных для вызова из обработчиков сигналов.
· #67Термин реальное время употребляется здесь неправильно, поскольку это расширение не делает попыток обеспечить гарантии времени задержки при доставке сигнала. Однако средства, которые оно добавляет, удобны для построения реализаций систем реального времени.
· #68До появления стандарта POSIX приложение могло обращаться к struct sigcontext
за информацией того же рода, что теперь представляет siginfo_t
, и термин "контекст" остался от этой старой реализации.
Этот третий параметр на самом деле указывает на структуру struct ucontext
, которая позволяет процессам выполнять полное переключение контекстов в пользовательском пространстве. Данные вопросы выходят за пределы тем, рассматриваемых в настоящей книге, но это хорошо документировано в Single Unix Specification.
Существует гораздо больше значений si_code
, нежели мы обсуждаем здесь, и эти значения имеют отношение к асинхронному вводу-выводу, очередям сообщений и таймерам реального времени, что выходит за границы тем, обсуждаемых в книге.
Он также принимает специальное значение SIGTRAP
, которое используется отладчиками, и SIGPOLL
, применяемое механизмом ненадежного асинхронного ввода-вывода. Ни один из них не описан в настоящей книге, поэтому подробности об этих сигналах не включены в табл. 12.3.
Вспомните, что SIGCHLD
посылается не только при завершении дочернего процесса, но и при его приостановке или возобновлении работы.
Дополнительные примеры обработки сигналов вы можете найти в программах для аренды файлов (глава 13), управления терминалом (глава 16) и работы с интервальными таймерами (глава 18).
· #74Это похоже на тип sigset_t
, используемый для шаблонов сигналов.
Когда сетевой сокет прослушивается (listen()
) и готов к приему (accept()
), считается, что он готов к считыванию для целей select()
; информацию о сокетах можно найти в главе 17.
Если сравнить это с параметром numfds
для poll()
, то можно понять, почему возникают затруднения.
Кроме некоторых экспериментальных ядер серии 2.1.
· #78Когда Линус Торвальдс впервые реализовал select()
, неспособность ядра BSD обновлять timeout
была отмечена как ошибка на man-странице для select()
. Вместо написания ошибочного кода Линус решил "исправить" эту ошибку. К сожалению, комитеты по стандартам одобрили поведение BSD.
Фактически ядро устанавливает обратный вызов для каждого файла, а затем, когда происходит событие, активизирует обратный вызов. Этот механизм устраняет проблемы масштабируемости при очень большом количестве файловых дескрипторов, поскольку опрос не используется в каждой точке.
· #80EPOLLET
— это еще одно значение, которое может иметь events
, переключающее epoll
с запуска уровнем на запуск фронтом сигнала. Эта тема выходит за рамки настоящей книги, и epoll
, запускаемую фронтом, следует применять только в особых случаях.
Структура, показанная в тексте, предоставляет правильные размеры элементов на большинстве платформ, но они неправильны для машин, в которых int
имеет 64 бита.
Эту программу необходимо запускать от имени root для наборов, содержащих более 1000 дескрипторов.
· #83Настоящее тестирование не гарантирует статистическую точность. Был проведен лишь один тестовый прогон, поэтому результаты поначалу будут неустойчивыми, что, однако, исчезнет после большого количества повторов.
· #84Сохранение копии памяти может показаться не столь важным, но благодаря эффективному механизму кэширования Linux, эти задержки копий являются самой медленной частью записи в файлы данных, в которых нет набора O_SYNC
.
Хотя большинство устройств символьного ввода-вывода не могут быть отображены, /dev/zero
отображается именно для этого типа приложений.
Ошибка сегментации возникнет при попытке доступа к нераспределенной странице.
· #87В будущем это может измениться, поскольку в ядре реализуются мелкомодульные системные полномочия.
· #88Файл /etc/passwd
обновляется только процессами, создающими новую копию файла с модификациями и затем заменяющими оригинал с помощью системного вызова rename()
. Поскольку такая последовательность является атомарной, процессы могут считывать из etc/passwd
в любое время.
Файловая система Andrew Filesystem (AFS), доступная в Linux, но не включенная в стандартное ядро, поддерживает O_EXCL
во всей сети.
Эта ситуация более сложна для потоков. Многие ядра и библиотеки Linux рассматривают потоки как разные процессы, что увеличивает потенциал возникновения конфликтов файловых блокировок между потоками (а это не совместимо со стандартной моделью потоков POSIX). Linux предлагает более традиционную модель потоков, при которой файловые блокировки разделяются между всеми потоками одного процесса, но в многопоточных программах лучше применять потоковые механизмы блокировки POSIX, а не полагаться на поведение файловых блокировок.
· #91Эта манипуляция блокировками происходит атомарно — не имеет значения, какая часть области разблокирована.
· #92Эффект, производимый вызовами fork()
и exec()
на файловые блокировки, является наиболее существенным отличием между файловой блокировкой POSIX (а, следовательно, и блокировкой lockf()
) и файловой блокировкой flock()
в BSD.
Одним из самых частых пользователей аренды файлов является файловый сервер Samba, позволяющий клиентам кэшировать свои записи для увеличения производительности.
· #94Если тот факт, что аренда записи уведомляет процесс об открытии файла для чтения, может показаться несколько странным, посмотрите на него с точки зрения процесса, получающего аренду. Ему необходимо знать, делает ли другой процесс читать файл, только в случае, когда основной процесс сам что-либо записывает в этот файл.
· #95Ядра предшествующих версий при успешной операции возвращает ноль либо единицу, тогда как более новые ядра всегда возвращают в данном случае ноль. В другом случае проверка на положительное или отрицательное значение работает нормально.
· #96Если один сигнал используется для аренды множества файлов, убедитесь, что сигнал является сигналом реального времени, так что множество событий аренды ставятся в очередь. Если используется обычный сигнал, он может потеряться либо события аренды могут возникать через очень короткие промежутки времени.
· #97До тех пор пока O_NONBLOCK
не будет определен как флаг open()
; в этом случае возвращается EWOULDBLOCK
.
Они так именуются, поскольку чтение разбрасывает данные по всей памяти, а запись собирает данные из разных областей памяти. Они также известны как векторное чтение и запись. Этим объясняется наличие "v" в конце readv()
и writev()
.
Эта эмулированная версия в большинстве случаев ведет себя корректно, но действует не так, как фактический системный вызов, если сигналы принимаются во время его выполнения.
· #100Это верно; PATH_MAX
не является фактическим пределом. POSIX считает его неопределенным, что обычно является эквивалентом "не используйте его".
Имя этого пути эквивалентно более простому /usr/bin/less
.
Функции ftw()
необходимо выполнять stat()
для каждого файла для выяснения, является ли он каталогом, и передача этой информации обратному вызову во многих случаях избавляет последний от необходимости повторного выполнения stat()
для файлов.
Это то же, что и метод, используемый для владения файлами (глава 13).
· #104Обработчик сигналов все еще следует регистрировать с помощью флага SA_SIGINFO
, чтобы файловый дескриптор надлежащим образом получил доступ к сигналу.
Остановленные процессы, однако, не могут генерировать сигналы, поэтому они также не могут перезапускаться.
· #106Обычно клавиатурной комбинацией приостановки является <Ctrl+Z>. Программа stty позволяет пользователям менять эту комбинацию. Подробнее это рассматривается в главе 16.
· #107То есть устройства, используемые как для ввода, так и для вывода.
· #108Реализации Unix старого типа предоставляли эту функцию с помощью TIOCSPGRP ioctl()
, до сих пор поддерживаемого Linux. Для сравнения, tcsetpgrp()
можно реализовать как ioctl(ttyfd, TIOCSPGRP, &pgrp)
.
Более подробно о сигналах и их взаимодействии с управлением заданиями рассказывается в главе 12.
· #110На man-странице setserial
описан способ обхода этого ограничения, специфический для Linux.
Обратите внимание: "бит в секунду" ("бит/с"), а не "бод". Бит в секунду определяет интенсивность передачи информации. Бод является техническим термином, описывающим смены фаз в течение секунды. Бод не соответствует termios
, но слово бод, к сожалению, попало в названия некоторых флагов termios
, не рассматриваемых в этой книге.
Например, приложения настройки сетевых протоколов, передающие информацию с помощью устройств tty.
· #113B134
в действительности равняется 134,5 бит/с, скорость, используемая устаревшим терминалом IBM.
Linux также использует c_cflag
для хранения скорости, но не стоит на это полагаться. Вместо этого применяйте cfsetospeed()
и cfstispeed()
.
Ядра 2.6.x, рассматриваемые в настоящей книге, поддерживают как версию 4, так и версию 6 (на последнюю обычно ссылаются как на IPv6 из набора TCP/IP).
· #116Кстати, именно так работают сети на основе коммутации пакетов. Альтернативная конструкция, сети с коммутацией каналов, более похожа на телефонные соединения. Однако они не часто используются при организации компьютерных сетей.
· #117Вот почему криптография приобрела такую значимость с тех пор как появилась всемирная сеть Internet.
· #118Многие высокоуровневые протоколы, такие как BOOTP и NFS, построены на основе UDP.
· #119Допустимы еще несколько значений данного параметра, однако они редко применяются в коде приложений.
· #120Системный вызов connect()
может также быть неблокируемым, что позволит пользователям гораздо быстрее открывать несколько TCP соединений (он позволяет продолжать работу программы, в то время как выполняется процесс синхронизации TCP). Подробности по этой теме можно найти в [33].
Различные формы select()
помечают сокет как открытый для чтения, тогда как accept()
не может блокировать его, даже если сокет не помечен как неблокируемый. Для обеспечения максимальной переносимости функцию select()
необходимо применять только для принятия соглашений с неблокируемыми сокетами, хотя в системе Linux это фактически не нужно. Причины этого подробно рассматриваются в [33].
Варианты BSD не поддерживают такую модель поведения, в таких системах ошибки проходят без отчетов.
· #123И для bind()
, и для connect()
процесс должен иметь права на выполнение для каталогов, через которые проходит поиск путевого имени (почти как при открытии стандартных файлов).
Исходя из условий реального мира, большинство серверных программ должны быть параллельными. Однако многие из них фактически созданы как итерационные сервера. Например, Web-серверы, в основном, обрабатывают только одно соединение за раз через данный процесс. Для того чтобы разрешить соединение нескольким клиентам, сервер организован в виде множества отдельных процессов. Это делает создание Web-сервера более простым. Если ошибка прерывает работу одного из таких процессов, она затрагивает только одно клиентское соединение.
· #125Это иногда называется передачей прав доступа.
· #126Несмотря на то что это может показаться очевидным, некоторые протоколы позволяют отправителю использовать любой порядок байтов и в зависимости от получателя преобразовывать информацию в соответствующем порядке. Это приводит к увеличению производительности, если взаимодействуют подобные механизмы, за счет повышения сложности алгоритма.
· #127Все процессоры Intel и совместимые с Intel хранят данные с прямым порядком байтов, поэтому здесь получение права преобразования очень важно для корректной работы программ.
· #128Информация о IANA доступна по адресу http://www.iana.org.
· #129Либо, все чаще и чаще, чтобы скрыть их от широкополосных поставщиков Internet-услуг, которые не хотят разрешить своим рядовым клиентам запускать серверы на домашних машинах.
· #130Однако она может оказаться троянским конем, запущенным привилегированным пользователем.
· #131Значения для неустановленных IPv4-адресов содержатся в константе INADDR_ANY
, которая является 32-битным числом.
Эти примеры взяты из документа RFC 1884, в котором определена структура адресации IPv6.
· #133Это так называемый неустановленный адрес для IPv6.
· #134Если у вас большой опыт в программировании сокетов (или вы сравниваете данную книгу с ее первым изданием), то вы обязательно заметите, что функции, применявшиеся для преобразования имен, значительно изменились. Эти изменения позволяют создавать программы абсолютно независимо от того протокола, который они используют. Теперь гораздо легче разрабатывать программы, работающие как на IPv4-, так и на IPv6-машинах. Они также должны распространяться на остальные протоколы, хотя функция getaddrinfo()
в данный момент работает только для IPv4 и IPv6.
Адрес обратной связи — это специальный адрес, который позволяет программам взаимодействовать через TCP/IP с приложениями только на одной и той же машине.
Для TCP-портов данная комбинация не может использоваться в течение двух минут.
· #137Это называется трехсторонним квитированием TCP, которое на самом деле проходит несколько сложнее, чем описано выше.
· #138Этот процесс называется сетевой загрузкой.
· #139UDP-сокеты, которые имеют постоянные пункты назначения, присвоенные через функцию connect()
, иногда называются присоединенными UDP-сокетами.
Есть также возможность превратить подключенный сокет в неподключенный с помощью функции connect()
, однако эта процедура не стандартизирована. Если вам все же необходимо ее применить, обратитесь к [33].
Данные функции могут применяться для передачи данных через любой сокет, и иногда возникают причины для использования их в TCP-соединениях.
· #142Возможно также применение системных вызовов sendmsg()
и recvmsg()
, однако необходимость в этом встречается редко.
Полное описание tftp можно найти в [33] и [34].
· #144Спецификация tftp-протокола требует, чтобы серверы посылали данные клиенту на номер порта, отличающийся от порта, на котором сервер ожидает новые соединения. При этом нетрудно создать параллельный сервер, поскольку каждый сокет сервера предназначен только для одного клиента.
· #145Применение этой структуры делает невозможным расширение данных функций на IPv6 без изменения их интерфейса.
· #146Функции, использующие статическую память для сохранения результатов, усложняют построение многопоточных приложений, поскольку в код приложения требуется добавлять блокировки для защиты этих статических буферов.
· #147Наверное, не существует IPv6-программ, использующих struct hostaddr
, однако они могут это делать. Функции, которые мы обсуждаем здесь, по умолчанию возвращают только информацию IPv4. Мы не будем рассматривать применение этих функций с IPv6.
UTC — Universal Coordinated Time (универсальное синхронизированное время), на которое иногда ошибочно ссылаются как на UCT, приблизительно эквивалентное среднему времени по Гринвичу (GMT) и зулу. Описание всех часовых поясов выходит за рамки материала, рассматриваемого в настоящей книге.
· #149Мы не рекомендуем применять библиотеку svgalib
для графического программирования. Во многих книгах описывается программирование для X Window System, и система X предоставляет более разумный, безопасный и мобильный метод программирования графики. С другой стороны, если вы действительно собираетесь программировать для сервера X Window, то не сможете обойтись без кодирования VC. Таким образом, в любом случае данная глава окажется полезной.
Прочтите man-страницы для утилит loadkeys
, dumpkeys
, keytables
, setfont
и mapscrn
.
Данный интерфейс имеет недостаток. Для него необходимо устанавливать некоторые постоянные доли секунды и осуществлять преобразование. Макрос HZ
больше не является константой даже на отдельной платформе. Однако, по крайней мере, для архитектуры Intel i86 Линус Торвальдс установил, что все определенные интерфейсы в отношении HZ
должны представлять синтетический интерфейс в 100 Гц. Возможно, что в будущем периодические системные часы исчезнут, в таком случае тики станут полностью искусственным понятием.
В большинстве остальных систем с виртуальными консолями или терминалами динамическое распределение для них не производится.
· #153Отдельные системы (но не Linux) инициируют автоматическое переключение, если вызывается консоль, которая не исполняется в текущий момент.
· #154Библиотека curses
определена в X/Open. Реализация, которая входит в состав Linux, представляет собой совместимую в данный момент с X/Open XSI Curses версию базового уровня.
Эта тема логически относится к главе 20, поскольку она имеет отношение к виртуальным консолям. Однако практический смысл вынуждает поместить этот раздел в данную главу — поскольку, как упоминалось во введении, настоящую книгу можно читать и выборочно.
· #156Популярным способом проверки в ранних ядрах Linux было создание последовательности абсолютно случайных байтов и запуск их на выполнение как программы. Кроме того, что таким методом невозможно сделать что-либо полезное, он довольно часто вызывает полную блокировку ядра. Поскольку попытки выполнения совершенно случайных последовательностей кодов не входят в "должностные инструкции" ядра, пользовательские программы не должны вызывать остановку корректной работы ядра. Таким образом, этот прием помогает находить большое число дефектов, которые необходимо устранить.
· #157Атака на программное обеспечение приложений сейчас является основным способом распространения вирусов.
· #158Системные квоты предотвращают возможность успешности такой атаки.
· #159Словарная атака — это довольно прямолинейный метод обнаружения паролей, когда автоматическая программа прогоняет огромный список обычных паролей (таких как слова в словаре) до тех пор, пока один из них не подойдет.
· #160ВООТР — это предшественник DHCP, позволяющий компьютерам автоматически узнавать свои IP-адреса при запуске сетевых интерфейсов.
· #161Функция alloca()
не является стандартным средством языка С, однако компилятор gcc предоставляет alloca()
в большинстве поддерживаемых операционных систем. В более старых версиях gcc (до версии 3.3) alloca()
не всегда должным образом взаимодействовала с массивами динамических размеров (другое расширение GNU), поэтому примите во внимание, что использовать нужно только одну из версий.
В некоторых устаревших версиях библиотеки С вместо этого возвращается -1 (если строка не помещается). Старая версия библиотеки С уже не поддерживается и не используется в защищенных программах, однако на man-странице по функции snprintf()
демонстрируется код, обрабатывающий оба варианта.
К сожалению, функция clearenv()
не очень хорошо стандартизирована. Она входит в последние версии POSIX, однако она была выброшена из стандарта Single Unix Standard и не доступна во всех системах типа Unix. Если вам необходимо поддерживать операционную систему, не включающую эту переменную, установите environ=NULL;
.
Существует еще несколько библиотечных функций, имеющих дело с временными файлами, такие как tmpnam()
, tempnam()
, mktemp()
и tmpfile()
. К сожалению, их применение приносит небольшую пользу, поскольку они могут привести к возникновению состязаний в программах, которые невнимательно реализованы.
Система Linux позволяет программам открывать очень большое количество файлов. Процессы, работающие как root, могут одновременно открывать сотни файлов, однако большинство дистрибутивов устанавливают предел ресурсов на количество файлов, который может открывать пользовательский процесс. Этот предел также ограничивает максимальный файловый дескриптор, который можно использовать, с помощью метода dup2()
, тем самым, предоставляя удобный верхний предел для закрывающего файлового дескриптора.
Еще одним способом закрытия всех файлов, открытых программой, является прохождение через каталог файловой системы процесса /proc
, в котором перечислены все открытые файлы, и закрытие каждого из них. Каталог /proc/PID/fd
(где PID
—это pid текущего процесса) содержит символическую ссылку для каждого файлового дескриптора, открытого процессом. Имя каждой символической ссылки представляет собой файловый дескриптор, которому она соответствует. Считывая содержимое каталога, программа легко может закрыть все файловые дескрипторы, которые больше не нужны.
Один из авторов этой книги разработал набор инструментальных средств newt
для управления окнами на высоком уровне на основе S-Lang; этот набор входит в состав большинства распространяемых дистрибутивов Linux.
Как это описано в базе данных terminfo
.
Ошибка возникает, если получение сигнала происходит в тот момент, когда S-Lang ожидает нажатие клавиши.
· #170Помните, что обновление физического терминала производится только с помощью функции SLsmg_refresh()
.
Со временем эта цифра может возрасти, однако маловероятно, что это когда-нибудь будет необходимо.
· #172В частности, в некоторых системах это может привести к мерцанию текста.
· #173Библиотека Berkley db была существенно расширена, и сейчас включает реализацию B-деревьев и весь спектр работы с транзакциями.
· #174В настоящее время Berkley db разрабатывается некоммерческой организацией, которая продает альтернативные лицензии для своей библиотеки, поэтому на них вполне можно ориентироваться при разработке определенного рода приложений.
· #175Инвертированные индексы представляют собой структуры данных, предназначенные для полнотекстового поиска.
· #176В отличие от некоторых библиотек баз данных, использующих множество файлов с расширениями .pag
и .dir
, библиотека Depot
использует один файл.
Хорошее описание хеш-таблиц можно найти в [11].
· #178Это значение можно изменить только путем оптимизации базы данных с помощью функции dpoptimize()
, описание которой можно найти на Web-сайте qdbm
.
Несмотря на то что qdbm
обеспечивает доступ к файловому дескриптору, использовать его следует осторожно. Дело в том, что все операции по чтению и записи в файл должны производиться через библиотеку qdbm
; операции, не связанные с изменением данных в файле, например, блокировка или установка флага для закрытия после выполнения, допускаются.
Вернее, они возвращаются в том порядке, в котором производятся ссылки на элементы из хеш-области. Хотя это и есть порядок, он является совершенно бесполезным.
· #181Библиотека glibc
также предлагает библиотеку argp
, с помощью которой можно осуществлять альтернативный вариант проверки синтаксиса параметров.
Те, кто знаком с функцией getopt()
, заметят, что argInfo
является единственным обязательным членом структуры struct poptOption
, который отличается от члена в таблице аргументов getoptlong()
. Благодаря этому сходству существенно упрощается переход от getoptlong()
к popt
.
Полный исходный код для данного примера можно найти в главе 23.
· #184Распространенной ошибкой является определение массива argv
как char **
, а не как const char **
, что является правильным вариантом. Благодаря прототипу функции poptGetContext()
компилятор генерирует предупреждающее сообщение, если массив argv
будет определен неправильно.
Он также добавляет параметр -?
, который соответствует --help
.
Макрос POPT_AUTOHELP
расширяется для включения вложенной таблицы параметров, определяющей новые параметры и обратный вызов, при котором реализуются эти параметры.
Часто в подобных случаях удобно использовать POPT_CONTEXT_KEEP_FIRST
.
Первоначально библиотека popt
была реализована для RPM, и многие параметры запросов RPM реализованы в виде простых макросов popt
.