13.5. Демон inetd

13.5. Демон inetd

В типичной системе Unix может существовать много серверов, ожидающих запроса клиента. Примерами являются FTP, Telnet, Rlogin, TFTP и т.д. В системах, предшествующих 4.3BSD, каждая из этих служб имела связанный с ней процесс. Этот процесс запускался во время загрузки из файла /etc/rc, и каждый процесс выполнял практически идентичные задачи запуска: создание сокета, связывание при помощи функции bind заранее известного порта с сокетом, ожидание соединения (TCP) или получения дейтаграммы (UDP) и последующее выполнение функции fork. Дочерний процесс выполнял обслуживание клиента, а родительский процесс ждал, когда поступит следующий запрос клиента. Эта модель характеризуется двумя недостатками.

1. Все демоны содержали практически идентичный код запуска, направленный сначала на создание сокета, а затем на превращение процесса в процесс демона (аналогично нашей функции daemon_init).

2. Каждый демон занимал некоторое место в таблице процессов, но при этом большую часть времени находился в состоянии ожидания.

Реализация 4.3BSD упростила ситуацию, предоставив суперсервер (superserver) Интернета — демон inetd. Этот демон может применяться серверами, использующими TCP или UDP, и не поддерживает других протоколов, таких как доменные сокеты Unix. Демон inetd решает две вышеупомянутые проблемы.

1. Он упрощает написание процессов демонов, поскольку обрабатывает большинство подробностей запуска. Таким образом устраняется необходимость вызова нашей функции daemon_init для каждого сервера.

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

Процесс inetd сам становится демоном, используя технологии, которые мы изложили при описании функции daemon_init. Затем он считывает и обрабатывает файл конфигурации, обычно файл /etc/inetd.conf. Этот файл задает, какие службы должен обрабатывать суперсервер, а также что нужно делать, когда приходит запрос к одной из этих служб. Каждая строка содержит поля, показанные в табл. 13.4. Вот несколько строк в качестве примера:

ftp    stream tcp nowait root   /usr/bin/ftpd ftpd -l

telnet stream tcp nowait root   /usr/bin/telnetd telnetd

login  stream tcp nowait root   /usr/bin/rlogind rlogind -s

tftp   dgram  udp wait   nobody /usr/bin/tftpd tftpd -s /tftpboot

Действительное имя сервера всегда передается в качестве первого аргумента программе, выполняемой с помощью функции exec.

Таблица 13.4. Поля файла inetd.conf

Поле Описание
service-name Должен быть в /etc/services
socket-type stream (TCP) или dgram (UDP)
Protocol Должен быть в /etc/protocols; либо tcp, либо udp
wait-flag Обычно nowait для TCP и wait для UDP
login-name Из /etc/password; обычно root
server-program Полное имя программы для вызова exec
server-program-arguments Аргументы программы для вызова exec

ПРИМЕЧАНИЕ

Таблица и приведенные строки — это только пример. Большинство производителей добавили демону inetd свои собственные функции. Примером может служить возможность обрабатывать серверы вызовов удаленных процедур (RPC) в дополнение к серверам TCP и UDP, а также возможность обрабатывать другие протоколы, отличные от TCP и UDP. Полное имя для функции exec и аргументы командной строки сервера, очевидно, зависят от приложения.

Флаг wait-flag может быть достаточно труден для понимания. Он указывает, собирается ли демон, запускаемый inetd, взять на себя работу с прослушиваемым сокетом. Сервисы UDP лишены деления на прослушиваемые и принятые сокеты, и потому практически всегда создаются с флагом wait-flag, равным wait. Сервисы TCP могут вести себя по-разному, но чаще всего для них указывается флаг wait-flag со значением nowait.

Взаимодействие IPv6 с файлом /etc/inetd.conf зависит от производителя. Иногда в качестве поля protocol указывается tcp6 или udp6, чтобы подчеркнуть, что для сервера должен быть создан сокет IPv6. Некоторые разрешают использовать значения protocol, равные tcp46 и udp46, если сервер готов принимать соединения по обоим протоколам. Специальные названия протоколов обычно не включаются в файл /etc/protocols.

Иллюстрация действий, выполняемых демоном inetd, представлена на рис. 13.1.

Рис. 13.1. Действия, выполняемые демоном inetd

1. При запуске демон читает файл /etc/inetd.conf и создает сокет соответствующего типа (потоковый или дейтаграммный сокет) для всех служб, заданных в файле. Максимальное число серверов, которые может обрабатывать демон inetd, зависит от максимального числа дескрипторов, которые он может создать. Каждый новый сокет добавляется к набору дескрипторов, который будет использован при вызове функции select.

2. Для каждого сокета вызывается функция bind, задающая заранее известный порт для сервера и универсальный IP-адрес. Этот номер порта TCP или UDP получается при вызове функции getservbyname с полями service-name и protocol из файла конфигурации в качестве аргументов.

3. Для сокетов TCP вызывается функция listen, так что принимаются входящие запросы на соединение. Этот шаг не выполняется для дейтаграммных сокетов.

4. После того как созданы все сокеты, вызывается функция select, ожидающая, когда какой-либо из сокетов станет готов для чтения. Вспомните (раздел 6.3), что прослушиваемый сокет TCP становится готов для чтения, когда новое соединение готово быть принятым с помощью функции accept, а сокет UDP становится готов для чтения, когда приходит дейтаграмма. Демон inetd большую часть времени блокирован в вызове функции select, ожидая, когда сокет станет готов для чтения.

5. При указании флага nowait для сокетов TCP вызывается функция accept сразу же, как только дескриптор сокета становится готов для чтения.

6. Демон inetd запускает функцию fork, и дочерний процесс обрабатывает запрос клиента. Это аналогично стандартному параллельному серверу (см. раздел 4.8).

Дочерний процесс закрывает все дескрипторы, кроме дескриптора, который он обрабатывает: новый присоединенный сокет, возвращаемый функцией accept для сервера TCP, или исходный сокет UDP. Дочерний процесс трижды вызывает функцию dup2, подключая сокет к дескрипторам 0, 1 и 2 (стандартные потоки ввода, вывода и сообщений об ошибках). Исходный дескриптор сокета затем закрывается. При этом в дочернем процессе открытыми остаются только дескрипторы 0, 1 и 2. Если дочерний процесс читает из стандартного потока ввода, он читает из сокета, и все, что он записывает в стандартный поток вывода или стандартный поток сообщений об ошибках, записывается в сокет. Дочерний процесс вызывает функцию getpwnam, чтобы получить значение поля login-name, заданного в файле конфигурации. Если это не поле root, дочерний процесс становится указанным пользователем при помощи функций setgid и setuid. (Поскольку процесс inetd выполняется с идентификатором пользователя, равным 0, дочерний процесс наследует этот идентификатор пользователя при выполнении функции fork, поэтому он имеет возможность стать любым пользователем по своему выбору.)

Теперь дочерний процесс вызывает функцию exec, чтобы выполнить соответствующую программу сервера (поле server-program) для обработки запроса, передавая аргументы, указанные в файле конфигурации.

7. Если сокет является потоковым сокетом, родительский процесс должен закрыть присоединенный сокет (как наш стандартный параллельный сервер). Родительский процесс снова вызывает функцию select, ожидая, когда следующий сокет станет готов для чтения.

Чтобы рассмотреть более подробно, что происходит с дескрипторами, на рис. 13.2 показаны дескрипторы демона inetd в момент прихода нового запроса на соединение от клиента FTP.

Рис. 13.2. Дескрипторы демона inetd в тот момент, когда приходит запрос на порт 21 TCP

Запрос на соединение направляется на порт 21 TCP; новый присоединенный сокет создается функцией accept.

На рис. 13.3 показаны дескрипторы в дочернем процессе после вызова функции fork, после того как дочерний процесс закрывает все остальные дескрипторы, кроме дескрипторов присоединенного сокета.

Рис. 13.3. Дескрипторы демона inetd в дочернем процессе

Следующий шаг для дочернего процесса — подключение присоединенного сокета к дескрипторам 0, 1 и 2 и последующее закрытие присоединенного сокета. При этом мы получаем дескрипторы, изображенные на рис. 13.4.

Рис. 13.4. Дескрипторы демона inetd после выполнения функции dup2

Затем дочерний процесс вызывает функцию exec, и, как сказано в разделе 4.7, во время выполнения функции exec все дескрипторы обычно остаются открытыми, поэтому реальный сервер, на котором выполняется функция exec, использует любой из дескрипторов 0, 1 и 2 для взаимодействия с клиентом. Эти дескрипторы должны быть единственными открытыми на стороне сервера дескрипторами.

Описанный нами сценарий относится к ситуации, при которой файл конфигурации задает в поле wait-flag значение nowait для сервера. Это типично для всех служб TCP и означает, что демону inetd не нужно ждать завершения его дочернего процесса, перед тем как он примет другое соединение для данной службы. Если приходит другой запрос на соединение для той же службы, он возвращается родительскому процессу, как только тот снова вызовет функцию select. Шаги 4, 5 и 6, перечисленные выше, выполняются снова, и новый запрос обрабатывается другим дочерним процессом.

Задание флага wait для дейтаграммного сервиса изменяет шаги, выполняемые родительским процессом. Флаг указывает на то, что демон inetd должен ждать завершения своего дочернего процесса, прежде чем снова вызвать функцию select для определения готовности этого сокета UDP для чтения. Происходят следующие изменения:

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

2. Родительский процесс отключает способность сокета выполнять последующие функции select, сбрасывая соответствующий бит в наборе дескрипторов с помощью макроса FD_CLR. Это значит, что дочерний процесс завладевает сокетом до своего завершения.

3. Когда завершается дочерний процесс, родительский процесс уведомляется об этом с помощью сигнала SIGCHLD, и обработчик сигналов родительского процесса получает идентификатор завершающегося дочернего процесса. Он снова включает функцию select для соответствующего сокета, устанавливая бит для этого сокета в своем наборе дескрипторов.

Причина, по которой дейтаграммный сервер должен завладевать сокетом, пока он не завершит работу, лишая тем самым демон inetd возможности выполнять функцию select на этом сокете для проверки готовности его для чтения (в ожидании другой дейтаграммы клиента), в том, что для сервера дейтаграмм существует только один сокет, в отличие от сервера TCP, у которого имеется прослушиваемый сокет и по одному присоединенному сокету для каждого клиента. Если демон inetd не отключил чтение на сокете дейтаграмм и, допустим, родительский процесс (inetd) завершил выполнение перед дочерним, дейтаграмма от клиента все еще будет находиться в приемном буфере сокета. Это приводит к тому, что функция select снова сообщает, что сокет готов для чтения, и демон inetd снова выполняет функцию fork, порождая другой (ненужный) дочерний процесс. Демон inetd должен игнорировать дейтаграммный сокет до тех пор, пока он не узнает, что дочерний процесс прочитал дейтаграмму из приемного буфера сокета. Демон inetd узнает, что дочерний процесс закончил работу с сокетом, путем получения сигнала SIGCHLD, указывающего на то, что дочерний процесс завершился. Подобный пример мы показываем в разделе 22.7.

Пять стандартных служб Интернета, описанных в табл. 2.1, обеспечиваются самим демоном inetd (см. упражнение 13.2).

Поскольку функцию accept для сервера TCP вызывает демон inetd (а не сам сервер), реальный сервер, запускаемый демоном inetd, обычно вызывает функцию getpeername для получения IP-адреса и номера порта клиента. Вспомните рис. 4.9, где мы показывали, что после выполнения вызовов fork и exec (что выполняет демон inetd) у реального сервера есть единственный способ получить идентификацию клиента — вызвать функцию getpeername.

Демон inetd обычно не используется для серверов, работающих с большими объемами данных, в особенности почтовыми серверами и веб-серверами. Например, функция sendmail обычно запускается как стандартный параллельный сервер, как мы отмечали в разделе 4.8. В этом режиме стоимость порождения процесса для каждого клиентского соединения равна стоимости функции fork, тогда как в случае сервера TCP, активизированного демоном inetd, — стоимости функций fork и exec. Веб-серверы используют множество технологий для минимизации накладных расходов при порождении процессов для обслуживания клиентов, как мы покажем в главе 30.

Поделитесь на страничке

Следующая глава >

Похожие главы из других книг

5.8.1. Демон Syslogd

Из книги Linux-сервер своими руками автора Колисниченко Денис Николаевич


5.8.5. Демон klogd

Из книги UNIX: взаимодействие процессов автора Стивенс Уильям Ричард

5.8.5. Демон klogd Демон klogd предназначен для перехвата и протоколирования сообщений ядра Linux (klogd расшифровывается как kernel-logging daemon). В своей работе вы можете использовать параметры демона, указанные в табл. 5.9.Параметры демона klogd Таблица 5.9 Параметр Описание -c n


8.1. Суперсерверы inetd и xinetd

Из книги Сетевые средства Linux автора Смит Родерик В.

8.1. Суперсерверы inetd и xinetd В данной главе пойдет речь об общей настройке Интернет-суперсерверов inetd и xinetd, а также о настройке сервера xinetd для работы с протоколом IPv6.Для начала все же определимся, почему inetd(xinetd) называется суперсервером? Да потому, что он отвечает за


8.1.1. Настройка сервера inetd

Из книги Linux: Полное руководство автора Колисниченко Денис Николаевич

8.1.1. Настройка сервера inetd Для начала разберемся с настройкой inetd. Этот сервер использовался в дистрибутиве RedHat до версии 7, в более новых версиях он заменен на xinetd (описание этого суперсервера приведено далее в п. 8.1.4…8.1.7). При конфигурирования inetd вам потребуется


8.1.4. Установкаx inetd

Из книги Linux глазами хакера автора Флёнов Михаил Евгеньевич

8.1.4. Установкаx inetd Суперсервер xinetd является достойной заменой inetd. Этот суперсервер, помимо всего прочего, обладает встроенными механизмами защиты, которые для inetd выполняет специальный демон tcpd. К тому же xinetd, в отличии от inetd, поддерживает IPv6. Даже если вы пока не


Inetd и серверы RPC

Из книги Операционная система UNIX автора Робачевский Андрей М.

Inetd и серверы RPC По умолчанию серверы, созданные с помощью rpcgen, могут вызываться сервером верхнего уровня inetd. Этот сервер описывается в разделе 12.5 [24]. Изучение содержимого заглушки сервера, создаваемой rpcgen, показывает, что при запуске функции main сервера она проверяет,


Использование inetd

Из книги UNIX: разработка сетевых приложений автора Стивенс Уильям Ричард

Использование inetd В обычных условиях программа-сервер связывается с некоторым портом (ресурсом, для идентификации которого используется тип протокола и число в интервале от 1 до 65535). В зависимости от номера порта, указанного в запросе, этот запрос направляется тому или


Формат файла /etc/inetd.conf

Из книги Разработка ядра Linux автора Лав Роберт

Формат файла /etc/inetd.conf Для настройки inetd используется конфигурационный файл /etc/inetd.conf. Если не принимать во внимание комментарии (строки, начинающиеся с символа #), то можно сказать, что содержимое файла inetd.conf представляет собой набор строк, каждая из которых определяет


19.2.1. Демон routed

Из книги автора

19.2.1. Демон routed Стандартной программой маршрутизации в Linux является демон routed. Этот демон, как правило, настраивается сам (динамически) и не требует конфигурирования. Обнаруженные маршруты он заносит в маршрутную таблицу ядра.В своей работе демон routed использует протокол


5.4. Демон inetd/xinetd

Из книги автора

5.4. Демон inetd/xinetd Для того чтобы сервер смог обрабатывать запросы клиентов, программа должна быть постоянно загружена и связана с определенным портом. В этом нет ничего сложного, но зачем постоянно держать программу в памяти, особенно если она слишком большая, а работает


Демон

Из книги автора

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


Глава 13 Процессы-демоны и суперсервер inetd

Из книги автора

Глава 13 Процессы-демоны и суперсервер inetd 13.1. Введение Демон (daemon) — это процесс, выполняющийся в фоновом режиме и не связанный с управляющим терминалом. Системы Unix обычно имеют множество процессов (от 20 до 50), которые являются демонами, работают в фоновом режиме и


13.2. Демон syslogd

Из книги автора

13.2. Демон syslogd Системы Unix обычно запускают демон syslogd в одном из сценариев инициализации системы, и он функционирует, пока система работает. Реализации syslogd, происходящие от Беркли, выполняют при запуске следующие действия:1. Считывается файл конфигурации, обычно /etc/syslog.conf,


Демон ksoftirqd

Из книги автора

Демон ksoftirqd Обработка отложенных прерываний (softirq) и, соответственно, тасклетов может осуществляться с помощью набора потоков пространства ядра (по одному потоку на каждый процессор). Потоки пространства ядра помогают обрабатывать отложенные прерывания, когда система


Демон pdflush

Из книги автора

Демон pdflush Измененные (dirty, "грязные") страницы памяти когда-нибудь должны быть записаны на диск. Обратная запись страниц памяти выполняется в следующих двух случаях.• Когда объем свободной памяти становится меньше определенного порога, ядро должно записать измененные