Шрифт:
30 exit(0);
31 }
32 Close(connfd); /* родительский процесс закрывает
присоединенный сокет */
33 }
34 }
Эта функция аналогична функции, показанной в листинге 5.9: она вызывает функцию
fork
для каждого клиентского соединения и обрабатывает сигналы SIGCHLD
, приходящие от закончивших свое выполнение дочерних процессов. Тем не менее мы сделали эту функцию не зависящей от протокола за счет вызова функции tcp_listen
. Мы не показываем обработчик сигнала sig_chld
: он совпадает с показанным в листинге 5.8, но только без функции printf
. Мы также перехватываем сигнал
SIGINT
, который генерируется при вводе символа прерывания. Мы вводим этот символ после завершения работы клиента, чтобы было выведено время, потраченное центральным процессором на выполнение данной программы. В листинге 30.3 показан обработчик сигнала. Это пример обработчика сигнала, который никогда не возвращает управление. Листинг 30.3. Обработчик сигнала SIGINT
//server/serv01.c
35 void
36 sig_int(int signo)
37 {
38 void pr_cpu_time(void);
39 pr_cpu_time;
40 exit(0);
41 }
В листинге 30.4 показана функция
pr_cpu_time
, вызываемая из обработчика сигнала. Листинг 30.4. Функция pr_cpu_time: вывод полного времени центрального процессора
//server/pr_cpu_time.c
1 #include "unp.h"
2 #include <sys/resource.h>
3 #ifndef HAVE_GETRUSAGE_PROTO
4 int getrusage(int, struct rusage*);
5 #endif
6 void
7 pr_cpu_time(void)
8 {
9 double user, sys;
10 struct rusage myusage, childusage;
11 if (getrusage(RUSAGE_SELF, &myusage) < 0)
12 err_sys("getrusage error");
13 if (getrusage(RUSAGE_CHILDREN, &childusage) < 0)
14 err_sys("getrusage error");
15 user = (double)myusage.ru_utime.tv_sec +
16 myusage.ru_utime.tv_usec / 1000000.0;
17 user += (double)childusage.ru_utime.tv_sec +
18 childusage.ru_utime.tv_usec / 1000000.0;
19 sys = (double)myusage.ru_stime.tv_sec +
20 myusage.ru_stime.tv_usec / 1000000.0;
21 sys += (double)childusage.ru_stime.tv_sec +
22 childusage.ru_stime.tv_usec / 1000000.0;
21 printf("\nuser time = %g, sys time = %g\n", user, sys);
22 }
Функция
getrusage
вызывается дважды: она позволяет получить данные об использовании ресурсов вызывающим процессом ( RUSAGE_SELF
) и всеми его дочерними процессами, которые завершили свое выполнение ( RUSAGE_CHILDREN
). Выводится время, затраченное центральным процессором на выполнение пользовательского процесса (общее пользовательское время, total user time), и время, которое центральный процессор затратил внутри ядра на выполнение задач, заданных вызывающим процессом (общее системное время, total system time). Возвращаясь к листингу 30.2, мы видим, что для обработки каждого клиентского запроса вызывается функция
web_child
. Эта функция показана в листинге 30.5. Листинг 30.5. Функция web_child: обработка каждого клиентского запроса
//server/web_child.c
1 #include "unp.h"
2 #define MAXN 16384 /* максимальное количество байтов, которое клиент
может запросить */
3 void
4 web_child(int sockfd)
5 {
6 int ntowrite;
7 ssize_t nread;
8 char line[MAXLINE], result[MAXN];
9 for (;;) {
10 if ((nread = Readline(sockfd, line, MAXLINE)) == 0)
11 return; /* соединение закрыто другим концом */