Литмир - Электронная Библиотека
Содержание  
A
A

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

main
для нашего параллельного сервера TCP.

Листинг 30.2. Функция main для параллельного сервера TCP

//server/serv01.c

 1 include "unp.h"

 2 int

 3 main(int argc, char **argv)

 4 {

 5  int listenfd, connfd;

 6  pid_t childpid;

 7  void sig_chld(int), sig_int(int), web_child(int);

 8  socklen_t clilen, addrlen;

 9  struct sockaddr *cliaddr;

10  if (argc == 2)

11   listenfd = Tcp_listen(NULL, argv[1], &addrlen);

12  else if (argc == 3)

13   listenfd = Tcp_listen(argv[1], argv[2], &addrlen);

14  else

15   err_quit("usage: serv01 [ <host> ] <port#>");

16  cliaddr = Malloc(addrlen);

17  Signal(SIGCHLD, sig_chld);

18  Signal(SIGINT, sig_int);

19  for (;;) {

20   clilen = addrlen;

21   if ((connfd = accept(listenfd, cliaddr, &clilen)) < 0) {

22    if (errno == EINTR)

23     continue; /* назад к for() */

24    else

25     err_sys("accept error");

26   }

27   if ((childpid = Fork()) == 0) { /* дочерний процесс */

28    Close(listenfd); /* закрываем прослушиваемый сокет */

29    web_child(connfd); /* обрабатываем запрос */

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.

345
{"b":"225366","o":1}