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

21  Signal (SIGINT, sig_int);

22  for (;;)

23   pause; /* дочерние процессы завершились */

24 }

11-18 Дополнительный аргумент командной строки указывает, сколько требуется создать дочерних процессов. В памяти выделяется место для размещения массива, в который записываются идентификаторы дочерних процессов, используемые функцией mainпри окончании работы программы для завершения этих процессов.

19-20 Каждый дочерний процесс создается функцией child_make, которую мы показываем в листинге 30.8.

Код обработчика сигнала SIGINT, представленный в листинге 30.7, отличается от кода, приведенного в листинге 30.3.

Листинг 30.7. Обработчик сигнала SIGINT

//server/serv02.c

25 void

26 sig_int(int signo)

27 {

28  int i;

29  void pr_cpu_time(void);

30  /* завершаем все дочерние процессы */

31  for (i = 0; i nchildren; i++)

32   kill(pids[i], SIGTERM);

33  while (wait(NULL) 0) /* ждем завершения всех дочерних процессов */

34   ;

35  if (errno != ECHILD)

36   err_sys("wait error");

37  pr_cpu_time;

38  exit(0);

39 }

30-34 Функция getrusageсообщает об использовании ресурсов всеми дочерними процессами, завершившимисвое выполнение, поэтому мы должны завершить все дочерние процессы к моменту вызова функции pr_cpu_time. Для этого дочерним процессам посылается сигнал SIGTERM, после чего мы вызываем функцию waitи ждем завершения выполнения дочерних процессов.

В листинге 30.8 показана функция child_make, вызываемая из функции main для порождения очередного дочернего процесса.

Листинг 30.8. Функция child_make: создание очередного дочернего процесса

//server/child02.c

 1 #include "unp.h"

 2 pid_t

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

 4 {

 5 pid_t pid;

 6 void child_main(int, int, int);

 7 if ( (pid = Fork) 0)

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

 9 child_main(i, listenfd, addrlen); /* никогда не завершается */

10 }

7-9Функция forkсоздает очередной дочерний процесс и возвращает родителю идентификатор дочернего процесса. Дочерний процесс вызывает функцию child_main, показанную в листинге 30.9, которая представляет собой бесконечный цикл.

Листинг 30.9. Функция child_main: бесконечный цикл, выполняемый каждым дочерним процессом

//server/child02.c

11 void

12 child_main(int i, int listenfd, int addrlen)

13 {

14  int connfd;

15  void web_child(int);

16  socklen_t clilen;

17  struct sockaddr *cliaddr;

18  cliaddr = Malloc(addrlen);

19  printf("child %ld starting\n", (long)getpid);

20  for (;;) {

21   clilen = addrlen;

22   connfd = Accept(listenfd, cliaddr, clilen);

23   web_child(connfd); /* обработка запроса */

24   Close(connfd);

25  }

26 }

20-25 Каждый дочерний процесс вызывает функцию accept, и когда она завершается, функция web_child(см. листинг 30.5) обрабатывает клиентский запрос. Дочерний процесс продолжает выполнение цикла, пока родительский процесс не завершит его.

<p>Реализация 4.4BSD</p>

Если вы никогда ранее не сталкивались с таким типом устройства сервера (несколько процессов, вызывающих функцию acceptна одном и том же прослушиваемом сокете), вас, вероятно, удивляет, что это вообще может работать. Пожалуй, здесь уместен краткий экскурс, описывающий реализацию этого механизма в Беркли-ядрах (более подробную информацию вы найдете в [128]).

Родитель сначала создает прослушиваемый сокет, а затем — дочерние процессы. Напомним, что каждый раз при вызове функции forkпроисходит копирование всех дескрипторов в каждый дочерний процесс. На рис. 30.2 показана организация структур proc(по одной структуре на процесс), одна структура fileдля прослушиваемого дескриптора и одна структура socket.

Рис. 30.2. Организация структур proc, file и socket

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

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

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

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

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

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

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

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

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