UNIX: разработка сетевых приложений
Задание флага
для дейтаграммного сервиса изменяет шаги, выполняемые родительским процессом. Флаг указывает на то, что демонwaitдолжен ждать завершения своего дочернего процесса, прежде чем снова вызвать функциюinetdдля определения готовности этого сокета UDP для чтения. Происходят следующие изменения:select1. После выполнения функции
в родительском процессе сохраняется идентификатор дочернего процесса. Это дает возможность родительскому процессу узнать, когда завершается определенный дочерний процесс, анализируя значение, возвращаемое функциейfork.waitpid2. Родительский процесс отключает способность сокета выполнять последующие функции
, сбрасывая соответствующий бит в наборе дескрипторов с помощью макросаselect. Это значит, что дочерний процесс завладевает сокетом до своего завершения.FD_CLR3. Когда завершается дочерний процесс, родительский процесс уведомляется об этом с помощью сигнала
, и обработчик сигналов родительского процесса получает идентификатор завершающегося дочернего процесса. Он снова включает функциюSIGCHLDдля соответствующего сокета, устанавливая бит для этого сокета в своем наборе дескрипторов.selectПричина, по которой дейтаграммный сервер должен завладевать сокетом, пока он не завершит работу, лишая тем самым демон
возможности выполнять функциюinetdна этом сокете для проверки готовности его для чтения (в ожидании другой дейтаграммы клиента), в том, что для сервера дейтаграмм существует только один сокет, в отличие от сервера TCP, у которого имеется прослушиваемый сокет и по одному присоединенному сокету для каждого клиента. Если демонselectне отключил чтение на сокете дейтаграмм и, допустим, родительский процесс (inetd) завершил выполнение перед дочерним, дейтаграмма от клиента все еще будет находиться в приемном буфере сокета. Это приводит к тому, что функцияinetdснова сообщает, что сокет готов для чтения, и демонselectснова выполняет функциюinetd, порождая другой (ненужный) дочерний процесс. Демонforkдолжен игнорировать дейтаграммный сокет до тех пор, пока он не узнает, что дочерний процесс прочитал дейтаграмму из приемного буфера сокета. Демонinetdузнает, что дочерний процесс закончил работу с сокетом, путем получения сигналаinetd, указывающего на то, что дочерний процесс завершился. Подобный пример мы показываем в разделе 22.7.SIGCHLDПять стандартных служб Интернета, описанных в табл. 2.1, обеспечиваются самим демоном
(см. упражнение 13.2).inetdПоскольку функцию
для сервера TCP вызывает демонaccept(а не сам сервер), реальный сервер, запускаемый демономinetd, обычно вызывает функциюinetdдля получения IP-адреса и номера порта клиента. Вспомните рис. 4.9, где мы показывали, что после выполнения вызововgetpeernameиfork(что выполняет демонexec) у реального сервера есть единственный способ получить идентификацию клиента — вызвать функциюinetd.getpeernameДемон
обычно не используется для серверов, работающих с большими объемами данных, в особенности почтовыми серверами и веб-серверами. Например, функцияinetdобычно запускается как стандартный параллельный сервер, как мы отмечали в разделе 4.8. В этом режиме стоимость порождения процесса для каждого клиентского соединения равна стоимости функцииsendmail, тогда как в случае сервера TCP, активизированного демономfork, — стоимости функцийinetdиfork. Веб-серверы используют множество технологий для минимизации накладных расходов при порождении процессов для обслуживания клиентов, как мы покажем в главе 30.exec13.6. Функция daemon_inetd
В листинге 13.3 показана функция
, которую мы можем вызвать с сервера, запущенного демономdaemon_inetd.inetdЛистинг 13.3. Функция daemon_inetd для придания свойств демона процессу, запущенному демоном inetd
//daemon_inetd.c1 #include "unp.h"2 #include <syslog.h>3 extern int daemon_proc; /* определено в error.c */4 void5 daemon_inetd(const char *pname, int facility)6 {7 daemon_proc = 1; /* для наших функций err_XXX() */8 openlog(pname, LOG_PID, facility);9 }Эта функция тривиальна по сравнению с
, потому что все шаги выполняются демономdaemon_initпри запуске. Все, что мы делаем, — устанавливаем флагinetdдля наших функций ошибок (см. табл. Г.1) и вызываем функциюdaemon_procс теми же аргументами, что и при вызове функцииopenlog, представленной в листинге 13.1.daemon_initПример: сервер времени и даты, активизированный демоном inetd
Листинг 13.4 представляет собой модификацию нашего сервера времени и даты, показанного в листинге 13.2, который может быть активизирован демоном
.inetdЛистинг 13.4. Не зависящий от протокола сервер времени и даты, который может быть активизирован демоном inetd
//inetd/daytimetcpsrv3.c1 #include "unp.h"2 #include <time.h>3 int4 main(int argc, char **argv)5 {6 socklen_t len;7 struct sockaddr *cliaddr;8 char buff[MAXLINE];9 time_t ticks;10 daemon_inetd(argv[0], 0);