Читаем UNIX: разработка сетевых приложений полностью

Рассмотрим сначала функцию child_make, которая приведена в листинге 30.17. Мы создаем канал и доменный сокет Unix (см. главу 14) перед вызовом функции fork. После того, как создан дочерний процесс, родительский процесс закрывает один дескриптор ( sockfd[1]), а дочерний процесс закрывает другой дескриптор ( sockfd[0]). Более того, дочерний процесс подключает свой дескриптор канала ( sockfd[1]) к стандартному потоку сообщений об ошибках, так что каждый дочерний процесс просто использует это устройство для связи с родительским процессом. Этот механизм проиллюстрирован схемой, приведенной на рис. 30.3.

Листинг 30.17. Функция child_make: передача дескриптора в сервере с предварительным порождением дочерних процессов

//server/child05.c

 1 #include "unp.h"

 2 #include "child.h"

 3 pid_t

 4 child_make(int i, int listenfd, int addrlen)

 5 {

 6  int sockfd[2];

 7  pid_t pid;

 8  void child_main(int, int, int);

 9  Socketpair(AF_LOCAL, SOCK_STREAM, 0, sockfd);

10  if ((pid = Fork) 0) {

11   Close(sockfd[1]);

12   cptr[i].child_pid = pid;

13   cptr[i].child_pipefd = sockfd[0];

14   cptr[i].child_status = 0;

15   return (pid); /* родительский процесс */

16  }

17  Dup2(sockfd[1], STDERR_FILENO); /* канал от дочернего процесса к

                                       родительскому */

18  Close(sockfd[0]);

19  Close(sockfd[1]);

20  Close(listenfd); /* дочернему процессу не требуется, чтобы

                        он был открыт */

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++) {

Перейти на страницу:

Похожие книги

Основы программирования в Linux
Основы программирования в Linux

В четвертом издании популярного руководства даны основы программирования в операционной системе Linux. Рассмотрены: использование библиотек C/C++ и стан­дартных средств разработки, организация системных вызовов, файловый ввод/вывод, взаимодействие процессов, программирование средствами командной оболочки, создание графических пользовательских интерфейсов с помощью инструментальных средств GTK+ или Qt, применение сокетов и др. Описана компиляция программ, их компоновка c библиотеками и работа с терминальным вводом/выводом. Даны приемы написания приложений в средах GNOME® и KDE®, хранения данных с использованием СУБД MySQL® и отладки программ. Книга хорошо структурирована, что делает обучение легким и быстрым. Для начинающих Linux-программистов

Нейл Мэтью , Ричард Стоунс , Татьяна Коротяева

ОС и Сети / Программирование / Книги по IT
1001 совет по обустройству компьютера
1001 совет по обустройству компьютера

В книге собраны и обобщены советы по решению различных проблем, которые рано или поздно возникают при эксплуатации как экономичных нетбуков, так и современных настольных моделей. Все приведенные рецепты опробованы на практике и разбиты по темам: аппаратные средства персональных компьютеров, компьютерные сети и подключение к Интернету, установка, настройка и ремонт ОС Windows, работа в Интернете, защита от вирусов. Рассмотрены не только готовые решения внезапно возникающих проблем, но и ответы на многие вопросы, которые возникают еще до покупки компьютера. Приведен необходимый минимум технических сведений, позволяющий принять осознанное решение.Компакт-диск прилагается только к печатному изданию книги.

Юрий Всеволодович Ревич

Программирование, программы, базы данных / Интернет / Компьютерное «железо» / ОС и Сети / Программное обеспечение / Книги по IT