Добавить в цитаты Настройки чтения

Страница 392 из 399

exit(main(argc, argv));

Следовательно, вызывается функция exit, а затем и программа очистки стандартного ввода-вывода.

Глава 15

15.1. Функция unlink удаляет имя файла из файловой системы, и когда клиент позже вызовет функцию co

15.2. Клиент не сможет соединиться с сервером с помощью функции co

15.3. При выводе адреса протокола клиента путем вызова функции sock_ntop мы получим сообщение datagram from (no pathname bound) (дейтаграмма от (имя не задано)), поскольку по умолчанию с сокетом клиента не связывается никакое имя.

Одним из решений является проверить доменный сокет Unix в функциях udp_client и udp_co

15.4. Даже если мы заставим сервер вернуть в функции write 1 байт на его 26- байтовый ответ, использование функции 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 приведена реализация данной программы.

Листинг Д.7. Определение фактического количества собранных в очередь соединений для различных значений аргумента backlog

//debug//backlog.c

 1 #include "unp.h"

 2 #define PORT 9999

 3 #define ADDR "127 0.0.1"

 4 #define MAXBACKLOG 100

 5 /* глобальные переменные */

 6 struct sockaddr_in serv;

 7 pid_t pid; /* дочерний процесс */

 8 int pipefd[2];

 9 #define pfd pipefd[1] /* сокет родительского процесса */

10 #define cfd pipefd[0] /* сокет дочернего процесса */

11 /* прототипы функций */

12 void do_parent(void);

13 void do_child(void);

14 int

15 main(int argc, char **argv)

16 {

17  if (argc != 1)

18   err_quit("usage: backlog");

19  Socketpair(AF_UNIX, SOCK_STREAM, 0, pipefd);

20  bzero(&serv, sizeof(serv));

21  serv.sin_family = AF_INET;

22  serv.sin_port = htons(PORT);

23  Inet_pton(AF_INET, ADDR, &serv.sin_addr);

24  if ((pid = Fork()) == 0)

25   do_child();

26  else

27  do_parent();

28  exit(0);

29 }

30 void

31 parent_alrm(int signo)

32 {

33  return; /* прерывание блокированной функции co

34 }