Шрифт:
он был открыт */
21 child_main(i, listenfd, addrlen); /* никогда не завершается */
22 }
Рис. 30.3. Канал после того, как дочерний и родительский процесс закрыли один конец
После создания всех дочерних процессов мы получаем схему, показанную на рис. 30.4. Мы закрываем прослушиваемый сокет в каждом дочернем процессе, поскольку только родительский процесс вызывает функцию
accept
. Мы показываем на рисунке, что родительский процесс должен обрабатывать прослушиваемый сокет, а также все доменные сокеты. Как можно догадаться, родительский процесс использует функцию select
для мультиплексирования всех дескрипторов. Рис. 30.4. Каналы после создания всех дочерних процессов
В листинге 30.18 показана функция
main
. В отличие от предыдущих версий этой функции, в данном случае в памяти размещаются все наборы дескрипторов и в каждом наборе включены все биты, соответствующие прослушиваемому сокету и каналу каждого дочернего процесса. Вычисляется также максимальное значение дескриптора и выделяется память для массива структур Child
. Основной цикл запускается при вызове функции select
. Листинг 30.18. Функция main, использующая передачу дескриптора
//server/serv05.c
1 #include "unp.h"
2 #include "child.h"
3 static int nchildren;
4 int
5 main(int argc, char **argv)
6 {
7 int listenfd, i, navail, maxfd, nsel, connfd, rc;
8 void sig_int(int);
9 pid_t child_make(int, int, int);
10 ssize_t n;
11 fd_set rset, masterset;
12 socklen_t addrlen, clilen;
13 struct sockaddr *cliaddr;
14 if (argc == 3)
15 listenfd = Tcp_listen(NULL, argv[1], &addrlen);
16 else if (argc == 4)
17 listenfd = Tcp_listen(argv[1], argv[2], &addrlen);
18 else
19 err_quit("usage; serv05 [ <host> ] <port#> <#children>");
20 FD_ZERO(&masterset);
21 FD_SET(listenfd, &masterset);
22 maxfd = listenfd;
23 cliaddr = Malloc(addrlen);
24 nchildren = atoi(argv[argc - 1]);
25 navail = nchildren;
26 cptr = Calloc(nchildren, sizeof(Child));
27 /* предварительное создание дочерних процессов */
28 for (i = 0; i < nchildren; i++) {
29 child_make(i, listenfd, addrlen); /* родительский процесс
завершается */
30 FD_SET(cptr[i].child_pipefd, &masterset);
31 maxfd = max(maxfd, cptr[i].child_pipefd);
32 }
33 Signal(SIGINT, sig_int);
34 for (;;) {
35 rset = masterset;
36 if (navail <= 0)
37 FD_CLR(listenfd, &rset); /* выключаем, если нет свободных
дочерних процессов */
38 nsel = Select(maxfd + 1, &rset, NULL, NULL, NULL);
39 /* проверка новых соединений */
40 if (FD_ISSET(listenfd, &rset)) {
41 clilen = addrlen;