Шрифт:
12 "<#loops/child> <#bytes/request>");
13 nchildren = atoi(argv[3]);
14 nloops = atoi(argv[4]);
15 nbytes = atoi(argv[5]);
16 snprintf(request, sizeof(request), "%d\n", nbytes); /* в конце
символ новой строки */
17 for (i = 0; i < nchildren; i++) {
18 if ((pid = Fork) == 0) { /* дочерний процесс */
19 for (j = 0; j < nloops; j++) {
20 fd = Tcp_connect(argv[1], argv[2]);
21 Write(fd, request, strlen(request));
22 if ((n = Readn(fd, reply, nbytes)) != nbytes)
23 err_quit("server returned %d bytes", n);
24 Close(fd); /* состояние TIME_WAIT на стороне клиента,
а не сервера */
25 }
26 printf("child %d done\n", i);
27 exit(0);
28 }
29 /* родительский процесс снова вызывает функцию fork */
30 }
31 while (wait(NULL) > 0) /* теперь родитель ждет завершения всех
дочерних процессов */
32 ;
33 if (errno != ECHILD)
34 err_sys("wait error");
35 exit(0);
36 }
10-12
Каждый раз при запуске клиента мы задаем имя узла или IP-адрес сервера, порт сервера, количество дочерних процессов, порождаемых функцией fork
(что позволяет нам инициировать несколько одновременных соединений с сервером), количество запросов, которое каждый дочерний процесс должен посылать серверу, и количество байтов, отправляемых сервером в ответ на каждый запрос.
17-30
Родительский процесс вызывает функцию fork
для порождения каждого дочернего процесса, и каждый дочерний процесс устанавливает указанное количество соединений с сервером. По каждому соединению дочерний процесс посылает запрос, задавая количество байтов, которое должен вернуть сервер, а затем дочерний процесс считывает это количество данных с сервера. Родительский процесс просто ждет завершения выполнения всех дочерних процессов. Обратите внимание, что клиент закрывает каждое соединение TCP, таким образом состояние TCP TIME_WAIT имеет место на стороне клиента, а не на стороне сервера. Это отличает наше клиент-серверное соединение от обычного соединения HTTP. При тестировании различных серверов из этой главы мы запускали клиент следующим образом:
% client 192.168.1.20 8888 5 500 4000
Таким образом создается 2500 соединений TCP с сервером: по 500 соединений от каждого из 5 дочерних процессов. По каждому соединению от клиента к серверу посылается 5 байт (
"4000\n"
), а от сервера клиенту передается 4000 байт. Мы запускаем клиент на двух различных узлах, соединяясь с одним и тем же сервером, что дает в сумме 5000 соединений TCP, причем максимальное количество одновременных соединений с сервером в любой момент времени равно 10. ПРИМЕЧАНИЕ
Для проверки различных веб-серверов существуют изощренные контрольные тесты. Один из них называется WebStone. Информация о нем находится в свободном доступе по адресуДля общего сравнения различных альтернативных устройств сервера, которые мы рассматриваем в этой главе, нам не нужны столь сложные тесты.
Теперь мы представим девять различных вариантов устройства сервера.
30.4. Последовательный сервер TCP