这个版本的tcpserv利用了signal函数来捕捉子进程终止信号SIGCHLD,并利用waitpid()对信号进行处理
#include "unp.h"
void str_echo(int sockfd)
{
ssize_t n;
char buf[MAXLINE];
again:
while((n = read(sockfd, buf, MAXLINE)) > 0)
Writen(sockfd, buf, n);
if(n < 0 && errno == EINTR)
goto again;
else if (n < 0)
err_sys("str_echo: read error");
}
void sig_chld(int signo)
{
pid_t pid;
int stat;
while((pid = waitpid(-1, &stat, WNOHANG)) > 0)
printf("child %d treminated\n", pid);
return;
}
int main(int argc, char const *argv[])
{
int listenfd, connfd;
char buff[MAXLINE];
pid_t childpid;
socklen_t clilen;
struct sockaddr_in cliaddr, servaddr;
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);
Signal(SIGCHLD, sig_chld); /* mast call waitpid() */
printf("---------------Waiting for connect------------\n");
for ( ; ;)
{
clilen = sizeof(cliaddr);
if((connfd = accept(listenfd, (SA *) &cliaddr, &clilen)) < 0)
{
if(errno == EINTR)
continue;
else
err_sys("accept error");
}
printf("Connect from: %s port: %d\n",
Inet_ntop(AF_INET, &cliaddr.sin_addr, buff, sizeof(buff)),
ntohs(cliaddr.sin_port));
if((childpid = Fork()) == 0)
{
Close(listenfd);
str_echo(connfd);
exit(0);
}
Close(connfd);
}
}
上述程序中的Signal函数对子进程产生的信号进行捕捉,在程序内部用waitpid()对信号处理,使已关闭的连接的子进程可以正常终止,避免了产生僵尸进程。