Некоторые версии нашего сервера работали с предварительно созданным пулом потоков или процессов. Интересным моментом является распределение клиентских запросов по потокам или дочерним процессам, находящимся в накопителе. В табл. 30.2 показаны варианты этого распределения, которые также будут обсуждаться в соответствующих разделах.

Таблица 30.2. Количество клиентов, обслуженных каждым из 15 дочерних процессов или потоков

№ процесса или потока Предварительное создание процессов без защиты accept (строка 2) Предварительное создание процессов с защитой accept (строка 3) Предварительное создание процессов, передача дескриптора (строка 5) Предварительное порождение потоков, защита accept (строка 7) 0 333 347 1006 333 1 340 328 950 323 2 335 332 720 333 3 335 335 583 328 4 332 338 485 329 5 331 340 457 322 6 333 335 385 324 7 333 343 250 360 8 332 324 105 341 9 331 315 32 348 10 334 326 14 358 11 333 340 9 331 12 334 330 4 321 13 332 331 1 329 14 332 336 0 320 5000 5000 5000 5000

30.2. Альтернативы для клиента TCP

Мы уже обсуждали различные способы устройства клиентов, но стоит тем не менее еще раз обратить внимание на относительные достоинства и недостатки этих способов.

1. В листинге 5.4 показан основной способ устройства клиента TCP. С этой программой были связаны две проблемы. Во-первых, когда она блокируется в ожидании ввода пользователя, она не замечает происходящих в сети событий, например отключения собеседника от соединения. Во-вторых, она действует в режиме остановки и ожидания, что неэффективно в случае пакетной обработки.

2. Листинг 6.1 содержит следующую, модифицированную версию клиента. С помощью функции select клиент получает информацию о событиях в сети во время ожидания ввода пользователя. Однако проблема этой версии заключается в том, что программа не способна корректно работать в пакетном режиме. В листинге 6.2 эта проблема решается путем применения функции shutdown.

3. С листинга 16.1 начинается рассмотрение клиентов, использующих неблокируемый ввод-вывод.

4. Первым из рассмотренных нами клиентов, вышедшим за пределы ограничений, связанных с наличием единственного процесса или потока для обслуживания всех запросов, является клиент, изображенный в листинге 16.6. В этом случае использовалась функция fork, и один процесс обрабатывал передачу данных от клиента к серверу, а другой — в обратном направлении.

5. В листинге 26.1 используются два потока вместо двух процессов.

В конце раздела 16.2 мы резюмируем различия между перечисленными версиями. Как мы отметили, хотя версия с неблокируемым вводом-выводом является самой быстродействующей, ее код слишком сложен, а применение двух потоков или двух процессов упрощает код.

30.3. Тестовый клиент TCP

В листинге 30.1[1] показан клиент, который будет использоваться для тестирования всех вариаций нашего сервера.

Листинг 30.1. Код клиента TCP для проверки различных версий сервера

//server/client.с

 1 #include "unp.h"

 2 #define MAXN 16384 /* максимальное количество байтов, которые могут быть

                         запрошены клиентом от сервера */

 3 int

 4 main(int argc, char **argv)

 5 {

 6  int i, j, fd, nchildren, nloops, nbytes;

 7  pid_t pid;

 8  ssize_t n,

 9   char request[MAXLINE], reply[MAXN];

10  if (argc != 6)

11   err_quit("usage: client <hostname or IPaddr> <port> <#children> "

12    "<#loops/child> <#bytes/request>");

13  nchildren = atoi(argv[3]);

14  nloops = atoi(argv[4]);

вернуться

1

Все исходные коды программ, опубликованные в этой книге, вы можете найти по адресу http://www.piter.com.


Перейти на страницу:
Изменить размер шрифта: