UNIX: разработка сетевых приложений - Страница 55
Доставка множества экземпляров одного и того же сигнала вызывает проблему, к рассмотрению которой мы и приступим.

Рис. 5.3. Клиент завершает работу, закрывая все пять соединений и завершая все пять дочерних процессов
Сначала мы запускаем сервер в фоновом режиме, а затем — новый клиент. Наш сервер, показанный в листинге 5.1, несколько модифицирован — теперь в нем вызывается функция
signalSIGCHLDlinux % tcpserv03 &[1] 20419linux % tcpcli04 206.62.226.35hello мы набираем эту строкуhello и она отражается сервером^D мы набираем символ конца файлаchild 20426 terminated выводится серверомПервое, что мы можем заметить, — данные выводит только одна функция
printfpsPID TTY TIME CMD20419 pts/6 00:00:00 tcpserv0320421 pts/6 00:00:00 tcpserv03 <defunct>20422 pts/6 00:00:00 tcpserv03 <defunct>20423 pts/6 00:00:00 tcpserv03 <defunct>Установки обработчика сигнала и вызова функции
waitПравильным решением будет вызвать функцию
waitpidwaitsigchldSIGCHLDwaitpidWNOHANGwaitpidwaitwaitВ листинге 5.9 показана окончательная версия нашего сервера. Он корректно обрабатывает возвращение ошибки
EINTRacceptwaitpidЛистинг 5.8. Окончательная (корректная) версия функции sig_chld, вызывающая функцию waitpid
//tcpcliserv/sigchldwaitpid.c 1 #include "unp.h" 2 void 3 sig_chld(int signo) 4 { 5 pid_t pid; 6 int stat; 7 while ((pid = waitpid(-1, &stat, WNOHANG)) >0) 8 printf("child %d terminatedn", pid); 9 return;10 }Листинг 5.9. Окончательная (корректная) версия TCP-сервера, обрабатывающего ошибку EINTR функции accept
//tcpcliserv/tcpserv04.c 1 #include "unp.h" 2 int 3 main(int argc, char **argv) 4 { 5 int listenfd, connfd; 6 pid_t childpid; 7 socklen_t clilen; 8 struct sockaddr_in cliaddr, servaddr; 9 void sig_chld(int);10 listenfd = Socket(AF_INET, SOCK_STREAM, 0);11 bzero(&servaddr, sizeof(servaddr));12 servaddr.sin_family = AF_INET;13 servaddr.sin_addr.s_addr = htonl(INADDR_ANY);14 servaddr.sin_port = htons(SERV_PORT);15 Bind(listenfd, (SA*)&servaddr, sizeof(servaddr));16 Listen(listenfd, LISTENQ);17 Signal(SIGCHLD, sig_chld); /* нужно вызвать waitpid() */18 for (;;) {19 clilen = sizeof(cliaddr);20 if ((connfd = accept(listenfd, (SA*)&cliaddr, &clilen)) < 0) {21 if (errno == EINTR)22 continue; /* назад к for() */23 else24 err_sys("accept error");25 }26 if ((childpid = Fork()) == 0) { /* дочерний процесс */