书中第5章Unix Network Programming Stevens et al 有一个服务端程序和一个客户端程序如下:
服务器
mysignal(SIGCHLD, sig_child);
for(;;)
{
connfd = accept(listenfd, (struct sockaddr *)&ca, &ca_len);
pid = fork();
if(pid == 0)
{
//sleep(60);
close(listenfd);
str_echo(connfd);
close(connfd);
exit(0);
}
close(connfd);
}
函数 sig_child 用于处理信号 SIGCHLD;代码如下:
void sig_child(int signo)
{
pid_t pid;
int stat;
static i = 1;
i++;
while(1)
{
pid = wait(&stat);
if(pid > 0)
{
printf("ith: %d, child %d terminated\n", i, pid);
}
else
{
break;
}
}
//pid = wait(&stat);
return;
}
客户端
for(i = 0 ; i < 5; i++)
{
sockfd[i] = socket(AF_INET, SOCK_STREAM, 0);
if(sockfd[i] < 0)
{
perror("create error");
exit(-1);
}
memset(&sa, 0, sizeof(sa));
sa.sin_family = AF_INET;
sa.sin_port = htons(5900);
if(inet_pton(AF_INET, argv[1], &sa.sin_addr) != 1)
{
perror("inet_pton error");
exit(-1);
}
connect(sockfd[i], (struct sockaddr *)&sa, sizeof(sa));
}
str_cli(sockfd[0], stdin);
exit(0);
在客户端的源码中可以看到,程序会与服务器端建立5个连接,但程序中只使用了1个连接; str_cli
完成后,调用 exit(0)
。并且应该关闭所有连接,然后服务器中的五个子进程将退出,并将 SIGCHLD 发送给父进程,父进程使用函数 sig_child
来处理 SIGCHLD。然后 while
循环将确认所有子进程都将被父进程正确等待。我对程序进行了几次测试;效果很好,所有的 child 都会被打扫干净。
但是在书中,作者写道“wait 无法正常工作,因为函数 wait 可能在所有子进程退出之前被阻塞”。那么书上的说法对吗?如果是对的,请您详细解释一下。 (PS:我认为 while
语句中的 wait
会正确处理所有子进程的退出。)
最佳答案
问题不在于 wait
,而在于信号传递。书中的sig_chld
函数没有while
循环,它只等待一个 child
void sig_child(int signo)
{
pid_t pid;
int stat;
pid = wait(&stat);
printf("child %d terminated\n", pid);
return;
}
当客户端退出时,所有连接都关闭,所有子连接最终终止。现在,第一个 SIGCHLD
信号被传递,并且在进入信号处理程序时,信号被阻塞。任何进一步的信号都不会排队,因此会丢失,从而导致服务器中的僵尸 child 。
您可以通过将 wait
包装在某个循环中来解决此问题,就像您所做的那样。另一种解决方案是显式忽略 SIGCHLD
,这在您不需要 child 的退出状态时有效。
虽然 wait
在一个循环中最终等待所有 child ,但它有一个缺点,即 wait
阻塞,如果还有 child 在运行。这意味着进程会卡在信号处理程序中,直到所有子进程都终止。
书上的解决方法是用waitpid
在循环中使用选项 WNOHANG
while ((pid = waitpid(-1, &stat, WNOHANG)) > 0)
printf("child %d terminated\n", pid);
这个循环等待所有终止的 child ,但会尽快退出,即使有正在运行的 child 也是如此。
要重现信号处理程序中挂起的服务器,您必须执行以下操作
- 启动服务器
- 开始第一个客户
- 启动第二个客户端
- 关闭其中一个客户
- 开始第三个客户
- 在第三个客户端输入文字
你不会得到回应
关于c - unix网络编程书中的wait函数?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23802864/