套接口编程理论基础:处理SIGCHLD信号

  我们不愿意留存僵尸进程,因为它们占用内核空间,最终导致我们耗尽进城资源。为防止子进程变为僵尸进程,fork生成的子进程都必须被wait。

#include    "unp.h"

int
main(int argc, char **argv)
{
int listenfd, connfd;
pid_t childpid;
socklen_t clilen;
struct sockaddr_in cliaddr, servaddr;
void sig_chld(int);

listenfd = Socket(AF_INET, SOCK_STREAM, 0);

bzero(&servaddr, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
servaddr.sin_port = htons(SERV_PORT);

Bind(listenfd, (SA *) &servaddr, sizeof(servaddr));

Listen(listenfd, LISTENQ);
/*在listen调用之后增加如下函数调用.这个函数必须在fork第一个子进程之前完成,且只做一次*/
Signal(SIGCHLD, sig_chld);

for ( ; ; ) {
clilen = sizeof(cliaddr);
connfd = Accept(listenfd, (SA *) &cliaddr, &clilen);

if ( (childpid = Fork()) == 0) { /* child process */
Close(listenfd); /* close listening socket */
str_echo(connfd); /* process the request */
exit(0);
}
Close(connfd); /* parent closes connected socket */
}
}

sig_chld函数

#include    "unp.h"

void
sig_chld(int signo)
{
pid_t pid;
int stat;

pid = wait(&stat);
printf("child %d terminated\n", pid);
return;
}

服务器端:
zhaoxj$ make tcpserv02
gcc -I../lib -g -O2 -D_REENTRANT -Wall -c -o tcpserv02.o tcpserv02.c
gcc -I../lib -g -O2 -D_REENTRANT -Wall -o tcpserv02 tcpserv02.o sigchldwait.o ../libunp.a -lpthread
zhaoxj$ ./tcpserv02 &
[3] 15339
客户端(再打开一个终端):
zhaoxj$ ./tcpcli01 127.0.0.1
hi
hi
^D <Ctr-D>结束客户终端
服务器端显示如下:
child 15343 terminated
具体过程:
1.键入EOF字符来终止客户。客户TCP发送一个FIN给服务器,服务器响应一个ACK。
2.服务器收到FIN后,发送一个EOF给子进程阻塞中的readline,子进程终止。
3.子进程终止时会产生SIGCHLD信号并发送给父进程,父进程正阻塞于accept调用。sig_chld函数执行,其wait调用取到子进程PID和终止
状态,随后printf调用

wait和waitpid函数 参照(APUE 进程控制)

。。。。。


原文地址:https://www.cnblogs.com/polestar/p/2405646.html