UNIX: разработка сетевых приложений
11 cliaddr = Malloc(MAXSOCKADDR);12 len = MAXSOCKADDR;13 Getpeername(0, cliaddr, &len);14 err_msg("connection from %s", Sock_ntop(cliaddr, len));15 ticks = time(NULL);16 snprintf(buff, sizeof(buff), "%.24s\r\n\", ctime(&ticks));17 Write(0, buff, strlen(buff));18 Close(0); /* закрываем соединение TCP */19 exit(0);20 }В программе сделано два важных изменения. Во-первых, исчез весь код создания сокета: вызовы функций
иtcp_listen. Эти шаги выполняются демономaccept, и мы ссылаемся на соединение TCP, используя нулевой дескриптор (стандартный поток ввода). Во-вторых, исчез бесконечный циклinetd, поскольку сервер активизируется по одному разу для каждого клиентского соединения. После предоставления сервиса клиенту сервер завершает свою работу.forВызов функции getpeernameПоскольку мы не вызываем функцию11-14, мы не знаем размера структуры адреса сокета, которую она возвращает, а поскольку мы не вызываем функциюtcp_listen, то не знаем и адреса протокола клиента. Следовательно, мы выделяем буфер для структуры адреса сокета, используя нашу константуacceptи вызываем функциюMAXSOCKADDRс нулевым дескриптором в качестве первого аргумента.getpeernameЧтобы выполнить этот пример в нашей системе Solaris, сначала мы присваиваем службе имя и порт, добавляя следующую строку в
:/etc/servicesmydaytime 9999/tcpЗатем добавляем строку в
:/etc/inetd.confmydaytime stream tcp nowait andy/home/andy/daytimetcpsrv3 daytimetcpsrv3(Мы разбили длинную строку на более короткие.) Мы помещаем выполняемый код в заданный файл и отправляем демону
сигналinetd, сообщающий ему, что нужно заново считать файл конфигурации. Следующий шаг — выполнить программуSIGHUP, чтобы проверить, что на порте TCP 9999 создан прослушиваемый сокет:netstatsolaris % <b>netstat -na | grep 9999</b>*.9999 *.* 0 0 49152 0 LISTENЗатем мы запускаем сервер с другого узла:
linux % <b>telnet solaris 9999</b>Trying 192.168.1.20...Connected to solaris.Escape character is '^]'.Tue Jun 10 11:04:02 2003Connection closed by foreign host.Файл
(в который, как указано в нашем файле/var/amd/messages, должны направляться наши сообщения с аргументом/etc/syslog.conf) содержит запись:facility=LOG_USERJun 10 11:04:02 solaris daytimetcpsrv3[28724]: connection from 192.168.1.10.5814513.7. Резюме
Демоны — это процессы, выполняемые в фоновом режиме независимо от управления с терминалов. Многие сетевые серверы работают как демоны. Все выходные данные демона обычно отправляются демону
при помощи вызова функцииsyslogd. Администратор полностью контролирует все, что происходит с этими сообщениями, основываясь на том, какой демон отправил данное сообщение и насколько оно серьезно.syslogЧтобы запустить произвольную программу и выполнять ее в качестве демона, требуется пройти несколько шагов: вызвать функцию
для запуска в фоновом режиме, вызвать функциюforkдля того, чтобы создать новый сеанс POSIX и стать главным процессом сеанса, снова вызвать функциюsetsid, чтобы избежать перехода в режим управления с терминала, изменить рабочий каталог и маску режима создания файла и закрыть все ненужные файлы. Наша функцияforkвыполняет все эти шаги.daemon_initМногие серверы Unix запускаются демоном
. Он осуществляет все необходимые шаги по превращению процесса в демон, и при запуске действительного сервера открывается сокет для стандартных потоков ввода, вывода и сообщений об ошибках. Это позволяет нам опустить вызовы функцийinetd,socket,bindиlisten, поскольку все эти шаги выполняются демономaccept.inetdУпражнения
1. Что произойдет в листинге 13.2, если мы отложим вызов функции
до завершения обработки аргументов командной строки и функцияdaemon_initбудет вызвана до того, как программа станет демоном?err_quit2. Как вы думаете, какие из 10 серверов, перечисленных в табл. 2.1 (учитываются версии TCP и UDP для каждой из пяти служб, управляемых демоном
), реализуются с помощью вызова функции fork, а какие не требуют этой функции?inetd3. Что произойдет, если мы создадим сокет UDP, свяжем порт 7 с сокетом (стандартный эхо-сервер в табл. 2.1) и отправим дейтаграмму UDP-серверу
?chargen4. В руководстве Solaris 2.x для демона
описывается флагinetd, заставляющий демон-tвызывать функциюinetd(с аргументамиsyslogиfacility=LOG_DAEMON) для протоколирования клиентского IP-адреса и порта любой службы TCP, которые обрабатывает демонlevel=LOG_NOTICE. Как демонinetdполучает эту информацию?inetdВ этом же руководстве сказано, что демон
не может выполнить это для сокета UDP. Почему?inetdЕсть ли способ обойти эти ограничения для служб UDP?
Глава 14
Дополнительные функции ввода-вывода
14.1. Введение
Эта глава охватывает разнообразные функции и технологии, которые мы помещаем в общую категорию «расширенного ввода-вывода». Сначала мы описываем установку тайм-аута для операции ввода-вывода, которую можно выполнить тремя различными способами. Затем мы рассматриваем три варианта функций
иread:writeиrecv, допускающие четвертый аргумент, содержащий флаги, передаваемые от процесса к ядру;sendиreadv, позволяющие нам задавать массив буферов для ввода или вывода;writevиrecvmsg, объединяющие все свойства других функций ввода-вывода и обладающие новой возможностью получения и отправки вспомогательных данных.sendmsg