#include "unp.h"
void
sig_chld(int signo)
{
pid_t pid;
int stat;
while ( (pid = waitpid(-1, &stat, WNOHANG)) > 0) /*参数 WNOHANG 表示采用非阻塞方式*/
printf("child %d terminated\n", pid);
return;
}
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);
Signal(SIGCHLD, sig_chld); /* 为防止子进程产生僵尸进行,必须调用waitpid函数进行清理*/
for ( ; ; ) {
clilen = sizeof(cliaddr);
if ( (connfd = accept(listenfd, (SA *) &cliaddr, &clilen)) < 0) {
if (errno == EINTR)
continue; /* back to for() */
else
err_sys("accept error");
}
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 */
}
}
备注:
1、采用fork复制进行,由于有两份资源,因此上面的描述符关闭都有两次,而描述符是被
内核引用计数的,因此,只有当两个都关闭时,内核才会真正关闭该描述符。
2、wait函数本身为阻塞方式,不足以防止僵尸进程出现,如,5个信号函数都在信号处理函数之前产生,
而信号处理函数只执行一次,剩下的就会成为僵尸。
阅读(1168) | 评论(0) | 转发(0) |