Книга: UNIX: разработка сетевых приложений

Распределение клиентских соединений между дочерними процессами

Распределение клиентских соединений между дочерними процессами

Следующей темой обсуждения является распределение клиентских соединений между свободными дочерними процессами, блокированными в вызове функции accept. Для получения этой информации мы модифицируем функцию main, размещая в совместно используемой области памяти массив счетчиков, которые представляют собой длинные целые числа (один счетчик на каждый дочерний процесс). Это делается следующим образом:

long *cptr, *meter(int); /* для подсчета количества клиентов на один
дочерний процесс */
cptr = meter(nchildren); /* перед порождением дочернего процесса */

В листинге 30.10 показана функция meter.

Листинг 30.10. Функция meter, которая размещает массив в совместно используемой памяти

//server/meter.c
 1 #include "unp.h"
 2 #include <sys/mman.h>
 3 /* Размещаем массив "nchildren" длинных целых чисел
 4  * в совместно используемой области памяти.
 5  * Эти числа используются как счетчики количества
    * клиентов, обслуженных данным дочерним процессом,
 6  * см. с. 467-470 книги [110]"
 7  */
 8 long*
 9 meter(int nchildren)
10 {
11  int fd;
12  long *ptr;
13 #ifdef MAP_ANON
14  ptr = Mmap(0, nchildren * sizeof(long), PROT_READ | PROT_WRITE,
15   MAP_ANON | MAP_SHARED, -1, 0);
16 #else
17  fd = Open("/dev/zero", O_RDWR, 0);
18  ptr = Mmap(0, nchildren * sizeof(long), PROT_READ | PROT_WRITE,
19   MAP_SHARED, fd, 0);
20  Close(fd);
21 #endif
22  return (ptr);
23 }

Мы используем неименованное отображение в память, если оно поддерживается (например, в 4.4BSD), или отображение файла /dev/zero (например, SVR4). Поскольку массив создается функцией mmap до того, как родительский процесс порождает дочерние, этот массив затем используется совместно родительским и всеми дочерними процессами, созданными функцией fork.

Затем мы модифицируем нашу функцию child_main (см. листинг 30.9) таким образом, чтобы каждый дочерний процесс увеличивал значение соответствующего счетчика на единицу при завершении функции accept, а после завершения выполнения всех дочерних процессов обработчик сигнала SIGINT выводил бы упомянутый массив счетчиков.

В табл. 30.2 показано распределение нагрузки по дочерним процессам. Когда свободные дочерние процессы блокированы вызовом функции accept, имеющийся в ядре алгоритм планирования равномерно распределяет нагрузку, так что в результате все дочерние процессы обслуживают примерно одинаковое количество клиентских запросов.

Оглавление книги


Генерация: 1.365. Запросов К БД/Cache: 3 / 0
поделиться
Вверх Вниз