35 void
36 do_parent(void)
27 {
38 int backlog, j, k, junk, fd[MAXBACKLOG + 1];
39 Close(cfd);
40 Signal(SIGALRM, parent_alrm);
41 for (backlog = 0; backlog <= 14; backlogs) {
42 printf("backlog = %d. ", backlog);
43 Write(pfd, &backlog. sizeof(int)); /* сообщение значения дочернему процессу */
44 Read(pfd, &junk, sizeof(int)); /* ожидание дочернего процесса */
45 for (j = 1; j <= MAXBACKLOG; j++) {
46 fd[j] = Socket(AF_INET, SOCK_STREAM, 0);
47 alarm(2);
48 if (connect(fd[j], (SA*)&serv, sizeof(serv)) < 0) {
49 if (errno != EINTR)
50 err_sys("connect error, j = %d", j);
51 printf("timeout, %d connections completed\n", j - 1);
52 for (k = 1; k <= j; k++)
53 Close(fd[k]);
54 break; /* следующее значение backlog */
55 }
56 alarm(0);
57 }
58 if (j > MAXBACKLOG)
59 printf("Id connections?\n", MAXBACKLOG);
60 }
61 backlog = -1; /* сообщаем дочернему процессу, что все сделано */
62 Write(pfd, &backlog, sizeof(int));
63 }
64 void
65 do_child(void)
66 {
67 int listenfd, backlog, junk;
68 const int on = 1;
69 Close(pfd);
70 Read(cfd, &backlog, sizeof(int)); /* ожидание родительского процесса */
71 while (backlog >= 0) {
72 listenfd = Socket(AF_NET, SOCK_STREAM, 0);
73 Setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
74 Bind(listenfd, (SA*)&serv, sizeof(serv));
75 Listen(listenfd, backlog); /* начало прослушивания */
76 Write(cfd, &junk, sizeof(int)); /* сообщение родительскому процессу */
77 Read(cfd, &backlog, sizeof(int)); /* ожидание родительского процесса */
78 Close(listenfd); /* также закрывает все соединения в очереди */
79 }
80 }
Глава 16
16.1. Дескриптор используется совместно родительским и дочерним процессами, поэтому его счетчик ссылок равен 2. Если родительский процесс вызывает функцию
close
, счетчик ссылок уменьшается с 2 до 1, и пока он больше нуля, сегмент FIN не посылается. Еще одна цель вызова функции
shutdown
— послать сегмент FIN, даже если дескриптор больше нуля.
16.2. Родительский процесс продолжит запись в сокет, получивший сегмент FIN, а первый сегмент, посланный серверу, вызовет получение сегмента RST в ответ. После этого функция
write
пошлет родительскому процессу сигнал
SIGPIPE
, как показано в разделе 5.12.
16.3. Когда дочерний процесс вызывает функцию
getppid
для отправки сигнала
SIGTERM
, возвращаемый идентификатор процесса будет равен 1. Это указывает на процесс
init
, наследующий все продолжающие работать дочерние процессы, родительские процессы которых завершились. Дочерний процесс будет пытаться послать сигнал процессу
init
, не имея необходимых прав доступа. Но если не исключается, что данный клиент будет запущен с правами привилегированного пользователя, позволяющими посылать сигналы процессу
init
, то возвращенное функцией
getppid
значение должно быть проверено перед отправкой сигнала.
16.4. Если удалить эти две строки, вызывается функция
select
. Но функция
select
немедленно завершится, поскольку соединение установлено и сокет открыт для записи. Эта проверка и оператор
goto
предотвращают ненужный вызов функции
select
.
16.5. Это может случиться, если сервер отправляет данные сразу, как только завершается его функция
accept
, и если узел клиента занят, когда приходит второй пакет трехэтапного рукопожатия для завершения соединения со стороны клиента (см. рис. 2.5). SMTP-серверы, например, немедленно отсылают клиенту сообщение по новому соединению, прежде чем произвести из него считывание.
Глава 17
17.1. Нет, это не имеет значения, поскольку первые три элемента объединения в листинге 17.1 являются структурами адреса сокета.
Глава 18
18.1. Элемент
sdl_nlen
будет равен 5, а элемент
sdl_alen
будет равен 8. Для этого требуется 21 байт, поэтому размер округляется до 24 байт [128, с. 89] в предположении, что используется 32-разрядная архитектура.
18.2. На этот сокет никогда не посылается ответ от ядра. Данный параметр сокета (
SO_USELOOPBACK
) определяет, посылает ли ядро ответ отправляющему процессу, как показано на с. 649-650 [128]. По умолчанию этот параметр включен, поскольку большинство процессов ожидают ответа. Но отключение данного параметра препятствует отправке ответов отправителю.
Глава 20
20.1. Если вы получаете большое количество ответов, они могут следовать каждый раз в разном порядке. Правда, отправляющий узел обычно выводится первым, поскольку дейтаграммы, направленные к нему или от него, не появляются в реальной сети.