Литмир - Электронная Библиотека
Содержание  
A
A

Пример: сервер времени и даты в качестве демона

В листинге 13.2 представлено изменение нашего сервера времени и даты, не зависящего от протокола. В отличие от сервера, показанного в листинге 11.8, в нем вызывается функция

daemon_init
, чтобы этот сервер мог выполняться в качестве демона.

Листинг 13.2. Не зависящий от протокола сервер времени и даты, работающий в качестве демона

//inetd/daytimetcpsrv2.c

 1 #include "unp.h"

 2 #include <time.h>

 3 int

 4 main(int argc, char **argv)

 5 {

 6  int listenfd, connfd;

 7  socklen_t addrlen, len;

 8  struct sockaddr *cliaddr;

 9  char buff[MAXLINE];

10  time_t ticks;

11  daemon_init(argv[0], 0);

12  if (argc == 2)

13   listenfd = Tcp_listen(NULL, argv[1], &addrlen);

14  else if (argc == 3)

15   listenfd = Tcp_listen(argv[1], argv[2], &addrlen);

16  else

17   err_quit("usage: daytimetcpsrv2 [ <host> ] <service or port>");

18  cliaddr = Malloc(addrlen);

19  for (;;) {

20   len = addrlen;

21   connfd = Accept(listenfd, cliaddr, &len);

22   err_msg("connection from %s", Sock_ntop(cliaddr, len));

23   ticks = time(NULL);

24   snprintf(buff, sizeof(buff), "%.24s\r\n", ctime(&ticks));

25   Write(connfd, buff, strlen(buff));

26   Close(connfd);

27  }

28 }

Изменений всего два: мы вызываем нашу функцию

daemon_init
, как только программа запускается, а затем вызываем нашу функцию
err_msg
вместо
printf
, чтобы вывести IP-адрес и порт клиента. На самом деле, если мы хотим, чтобы наши программы могли выполняться как демоны, мы должны исключить вызов функций
printf
и
fprintf
и вместо них использовать нашу функцию
err_msg
.

Обратите внимание, что мы проверяем argc и выводим соответствующее сообщение до вызова

daemon_init
. Таким образом пользователь, запустивший демона, получает немедленное уведомление о недопустимом количестве аргументов. После вызова
daemon_init
все сообщения направляются в системный журнал.

Если мы запустим эту программу на нашем узле

linux
и затем проверим файл
/var/log/messages
(куда мы отправляем все сообщения
LOG_USER
) после соединения с тем же узлом, мы получим:

Jul 10 09:54:37 linux daytimetcpsrv2[24288]: connection from 127.0.0.1.55862

Дата, время и имя узла автоматически ставятся в начале сообщения демоном

syslogd
.

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
150
{"b":"225366","o":1}