Чтобы выполнить этот пример в нашей системе Solaris, сначала мы присваиваем службе имя и порт, добавляя следующую строку в
/etc/services
:
mydaytime 9999/tcp
Затем добавляем строку в
/etc/inetd.conf
:
mydaytime stream tcp nowait andy
/home/andy/daytimetcpsrv3 daytimetcpsrv3
(Мы разбили длинную строку на более короткие.) Мы помещаем выполняемый код в заданный файл и отправляем демону
inetd
сигнал
SIGHUP
, сообщающий ему, что нужно заново считать файл конфигурации. Следующий шаг — выполнить программу
netstat
,
чтобы проверить, что на порте TCP 9999 создан прослушиваемый сокет:
solaris % netstat -na | grep 9999
*.9999 *.* 0 0 49152 0 LISTEN
Затем мы запускаем сервер с другого узла:
linux % telnet solaris 9999
Trying 192.168.1.20...
Connected to solaris.
Escape character is '^]'.
Tue Jun 10 11:04:02 2003
Connection closed by foreign host.
Файл
/var/amd/messages
(в который, как указано в нашем файле
/etc/syslog.conf
, должны направляться наши сообщения с аргументом
facility=LOG_USER
) содержит запись:
Jun 10 11:04:02 solaris daytimetcpsrv3[28724]: connection from 192.168.1.10.58145
13.7. Резюме
Демоны — это процессы, выполняемые в фоновом режиме независимо от управления с терминалов. Многие сетевые серверы работают как демоны. Все выходные данные демона обычно отправляются демону
syslogd
при помощи вызова функции
syslog
. Администратор полностью контролирует все, что происходит с этими сообщениями, основываясь на том, какой демон отправил данное сообщение и насколько оно серьезно.
Чтобы запустить произвольную программу и выполнять ее в качестве демона, требуется пройти несколько шагов: вызвать функцию
fork
для запуска в фоновом режиме, вызвать функцию
setsid
для того, чтобы создать новый сеанс POSIX и стать главным процессом сеанса, снова вызвать функцию
fork
, чтобы избежать перехода в режим управления с терминала, изменить рабочий каталог и маску режима создания файла и закрыть все ненужные файлы. Наша функция
daemon_init
выполняет все эти шаги.
Многие серверы Unix запускаются демоном
inetd
. Он осуществляет все необходимые шаги по превращению процесса в демон, и при запуске действительного сервера открывается сокет для стандартных потоков ввода, вывода и сообщений об ошибках. Это позволяет нам опустить вызовы функций
socket
,
bind
,
listen
и
accept
, поскольку все эти шаги выполняются демоном
inetd
.
Упражнения
1. Что произойдет в листинге 13.2, если мы отложим вызов функции
daemon_init
до завершения обработки аргументов командной строки и функция
err_quit
будет вызвана до того, как программа станет демоном?
2. Как вы думаете, какие из 10 серверов, перечисленных в табл. 2.1 (учитываются версии TCP и UDP для каждой из пяти служб, управляемых демоном
inetd
), реализуются с помощью вызова функции fork, а какие не требуют этой функции?
3. Что произойдет, если мы создадим сокет UDP, свяжем порт 7 с сокетом (стандартный эхо-сервер в табл. 2.1) и отправим дейтаграмму UDP-серверу
chargen
?
4. В руководстве Solaris 2.x для демона
inetd
описывается
флаг
– t
, заставляющий демон
inetd
вызывать функцию
syslog
(с аргументами
facility=LOG_DAEMON
и
level=LOG_NOTICE
) для протоколирования клиентского IP-адреса и порта любой службы TCP, которые обрабатывает демон
inetd
. Как демон
inetd
получает эту информацию?
В этом же руководстве сказано, что демон
inetd
не может выполнить это для сокета UDP. Почему?
Есть ли способ обойти эти ограничения для служб UDP?
Глава 14
Дополнительные функции ввода-вывода
14.1. Введение
Эта глава охватывает разнообразные функции и технологии, которые мы помещаем в общую категорию «расширенного ввода-вывода». Сначала мы описываем установку тайм-аута для операции ввода-вывода, которую можно выполнить тремя различными способами. Затем мы рассматриваем три варианта функций
read
и
write
:
recv
и
send
, допускающие четвертый аргумент, содержащий флаги, передаваемые от процесса к ядру;
readv
и
writev
, позволяющие нам задавать массив буферов для ввода или вывода;
recvmsg
и
sendmsg
, объединяющие все свойства других функций ввода-вывода и обладающие новой возможностью получения и отправки вспомогательных данных.
Мы также рассказываем о том, как определить, сколько данных находится в приемном буфере сокета и как использовать с сокетами стандартную библиотеку ввода-вывода С, и обсуждаем более совершенные способы ожидания событий.
14.2. Тайм-ауты сокета
Существует три способа установки тайм-аута для операции ввода-вывода через сокет.
1. Вызов функции
alarm
, которая генерирует сигнал
SIGALRM
, когда истекает заданное время. Это подразумевает обработку сигналов, которая может варьироваться от одной реализации к другой. К тому же такой подход может стать помехой другим существующим вызовам функции
alarm
в данном процессе.
2. Блокирование при ожидании ввода-вывода в функции
select
, имеющей встроенное ограничение времени, вместо блокирования в вызове функции
read
или
write
.
3. Использование более новых параметров сокета —
SO_RCVTIMEO
и
SO_SNDTIMEO
. Проблема при использовании этого подхода заключается в том, что не все реализации поддерживают новые параметры сокетов.
Все три технологии работают с функциями ввода и вывода (такими как
read
,
write
и их вариациями, например
recvfrom
и
sendto
), но нам также хотелось бы иметь технологию, работающую с функцией
connect
, поскольку процесс соединения TCP может занять длительное время (обычно 75 с). Функцию
select
можно использовать для установки тайм-аута функции
connect
, только когда сокет находится в неблокируемом режиме (который мы рассматриваем в разделе 16.3), а параметры сокетов, устанавливающие тайм-аут, не работают с функцией
connect
. Мы также должны отметить, что первые две технологии работают с любым дескриптором, в то время как третья технология только с дескрипторами сокетов.