UNIX: разработка сетевых приложений
35 void36 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 void65 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. Если родительский процесс вызывает функцию
, счетчик ссылок уменьшается с 2 до 1, и пока он больше нуля, сегмент FIN не посылается. Еще одна цель вызова функцииclose— послать сегмент FIN, даже если дескриптор больше нуля.shutdown16.2. Родительский процесс продолжит запись в сокет, получивший сегмент FIN, а первый сегмент, посланный серверу, вызовет получение сегмента RST в ответ. После этого функция
пошлет родительскому процессу сигналwrite, как показано в разделе 5.12.SIGPIPE16.3. Когда дочерний процесс вызывает функцию
для отправки сигналаgetppid, возвращаемый идентификатор процесса будет равен 1. Это указывает на процессSIGTERM, наследующий все продолжающие работать дочерние процессы, родительские процессы которых завершились. Дочерний процесс будет пытаться послать сигнал процессуinit, не имея необходимых прав доступа. Но если не исключается, что данный клиент будет запущен с правами привилегированного пользователя, позволяющими посылать сигналы процессуinit, то возвращенное функциейinitзначение должно быть проверено перед отправкой сигнала.getppid16.4. Если удалить эти две строки, вызывается функция
. Но функцияselectнемедленно завершится, поскольку соединение установлено и сокет открыт для записи. Эта проверка и операторselectпредотвращают ненужный вызов функцииgoto.select16.5. Это может случиться, если сервер отправляет данные сразу, как только завершается его функция
, и если узел клиента занят, когда приходит второй пакет трехэтапного рукопожатия для завершения соединения со стороны клиента (см. рис. 2.5). SMTP-серверы, например, немедленно отсылают клиенту сообщение по новому соединению, прежде чем произвести из него считывание.acceptГлава 17
17.1. Нет, это не имеет значения, поскольку первые три элемента объединения в листинге 17.1 являются структурами адреса сокета.
Глава 18
18.1. Элемент
будет равен 5, а элементsdl_nlenбудет равен 8. Для этого требуется 21 байт, поэтому размер округляется до 24 байт [128, с. 89] в предположении, что используется 32-разрядная архитектура.sdl_alen18.2. На этот сокет никогда не посылается ответ от ядра. Данный параметр сокета (
) определяет, посылает ли ядро ответ отправляющему процессу, как показано на с. 649-650 [128]. По умолчанию этот параметр включен, поскольку большинство процессов ожидают ответа. Но отключение данного параметра препятствует отправке ответов отправителю.SO_USELOOPBACKГлава 20
20.1. Если вы получаете большое количество ответов, они могут следовать каждый раз в разном порядке. Правда, отправляющий узел обычно выводится первым, поскольку дейтаграммы, направленные к нему или от него, не появляются в реальной сети.