13.4. IP-адрес и номер порта клиента могут быть получены из структуры адреса сокета, заполняемой функцией accept
Причина, по которой демон inetd
recvfrom
) осуществляется с помощью функции exec
сервером, а не самим демоном inetd
.Демон inetd
MSG_PEEK
(см. раздел 14.7), только чтобы получить IP-адрес и номер порта клиента, но оставляет саму дейтаграмму для чтения серверу.Глава 14
14.1. Если не установлен обработчик, первый вызов функции signal
SIG_DFL
, а вызов функции signal
для восстановления обработчика просто вернет его в исходное состояние.14.3. Приведем цикл for
for (;;) {
if ((n = Recv(sockfd, recvline, MAXLINE, MSG_PEEK)) == 0)
break; /* сервер закрыл соединение */
Ioctl(sockfd, FIONREAD, &npend);
printf("%d bytes from PEEK, %d bytes pending\n", n, npend);
n = Read(sockfd, recvline, MAXLINE);
recvline[n] = 0; /* завершающий нуль */
Fputs(recvline, stdout);
}
14.4. Данные продолжают выводиться, поскольку выход из функции main
main
вызывается программой запуска на языке С следующим образом:exit(main(argc, argv));
Следовательно, вызывается функция exit
Глава 15
15.1. Функция unlink
connect
, она не выполнится. Это не влияет на прослушиваемый сокет сервера, но клиенты не смогут выполнить функции connect
после вызова функции unlink
.15.2. Клиент не сможет соединиться с сервером с помощью функции connect
connect
доменный сокет Unix должен быть открыт и связан с этим полным именем (см. раздел 15.4).15.3. При выводе адреса протокола клиента путем вызова функции sock_ntop
datagram from (no pathname bound)
(дейтаграмма от (имя не задано)), поскольку по умолчанию с сокетом клиента не связывается никакое имя.Одним из решений является проверить доменный сокет Unix в функциях udp_client
udp_connect
и связать с сокетом при помощи функции bind
временное полное имя. Это приведет к зависимости от протокола в библиотечной функции, но не в нашем приложении.15.4. Даже если мы заставим сервер вернуть в функции write
sleep
на стороне клиента гарантирует, что все 26 сегментов будут получены до вызова функции read
, в результате чего функция read
вернет полный ответ. Это еще одно подтверждение того, что TCP является потоком байтов с отсутствием границ записей.Чтобы использовать доменные протоколы Unix, запускаем клиент и сервер с двумя аргументами командной строки /lосаl
/unix
) и /tmp/daytime
(или любое другое временное имя, которое вы хотите использовать). Ничего не изменится: 26 байт будут возвращаться функцией read
каждый раз, когда будет запускаться клиент.Поскольку для каждой функции send
MSG_EOR
, каждый байт рассматривается как логическая запись, и функция read
при каждом вызове возвращает 1 байт. Причина в том, что Беркли-реализации поддерживают флаг MSG_EOR
по умолчанию. Однако этот факт не документирован и не может использоваться в серийном коде. В данном примере мы используем эту особенность, чтобы показать разницу между потоком байтов и ориентированным на записи протоколом. С точки зрения реализации, каждая операция вывода идет в mbuf
(буфер памяти) и флаг MSG_EOR
сохраняется ядром вместе с mbuf
, когда mbuf
переходит из отправляющего сокета в приемный буфер принимающего сокета. Когда вызывается функция read, флаг MSG_EOR
все еще присоединен к каждому mbuf
, так что основная подпрограмма ядра read
(поддерживающая флаг MSG_EOR
, поскольку некоторые протоколы используют этот флаг) сама возвращает каждый байт. Если бы вместо read
мы использовали recvmsg
, флаг MSG_EOR
возвращался бы в поле msg_flags
каждый раз, когда recvmsg
возвращала бы 1 байт. Такой подход в TCP не срабатывает, поскольку отправляющий TCP не анализирует флаг MSG_EOR
в отсылаемом mbuf
и в любом случае у нас нет возможности передать этот флаг принимающему TCP в TCP-заголовке. (Выражаем благодарность Мату Томасу (Matt Thomas) за то, что он указал нам это недокументированное «средство».)15.5. В листинге Д.7 приведена реализация данной программы.