这是我的代码片段:
signal (SIGINT, ( void *)sig_handler);
while(1){
newsockd = -1;
memset(&cli_addr, 0, sizeof(cli_addr));
if((newsockd = accept(sockd, (struct sockaddr *) &cli_addr, (socklen_t *) &socket_len)) < 0){
perror("Errore nella connessionen");
onexit(newsockd, sockd, 0, 2);
}
fprintf(stdout, "Ricevuta richiesta di connessione dall' indirizzo %sn", inet_ntoa(cli_addr.sin_addr));
child_pid = fork();
if(child_pid < 0){
perror("Fork error");
onexit(newsockd, sockd, 0, 2);
}
if(child_pid == 0){
do_child(newsockd);
exit(0);
}
else{
while(waitpid(child_pid, NULL, WNOHANG) > 0)
continue;
}
}
}
和函数sig_handler:
void sig_handler(const int signo, const int sockd, const int newsockd){
if (signo == SIGINT){
printf("Received SIGINT, exiting..n");
if(newsockd) close(newsockd);
if(sockd) close(sockd);
exit(EXIT_SUCCESS);
}
}
当我按下"CTRL+C"时就会出现问题,因为sighandler被调用了多次
示例:
- 服务器正在侦听
- 收到2个连接
- 2个儿童叉子
- 2个儿童关闭
- 现在我想关闭服务器,所以我按下CTRL+C
预期输出:received SIGINT, exiting....
实际输出:received SIGINT, exiting....
received SIGINT, exiting....
received SIGINT, exiting....
我为什么会有这种行为?
编辑:代码已更新
这就是当1个分叉完成时发生的情况,当孩子完成时,我关闭服务器:
^C7518
7516
Received SIGINT, exiting...
Received SIGINT, exiting...
找到解决方案:问题是我没有在指令do_child()
之后写exit(0)
。。。代码已更新
信号被发送到当前进程的每个子进程
在您的代码中,当您使用fork
时,您将创建一个从主进程继承SIGINT
处理程序的子进程。这就是消息被打印多次的原因。
很少有观测结果,
1) 您应该更好地使用sigaction而不是信号函数。http://pubs.opengroup.org/onlinepubs/7908799/xsh/sigaction.html
2) 现在对当前代码进行一些修复。您可以使用
if(child_pid == 0)
{
/*Now in the child make again the action for SIGINT default, so that
your handler does not get called.*/
signal (SIGINT, SIG_DFL);
do_child(newsockd);
}
3) 为什么在主循环中调用waitpid?你应该有一个SIGCHLD的处理程序,然后在里面使用wait/waitpid
理想情况下,在创建了一个子服务客户端之后,主循环应该返回到accept。(如果它在创建子服务器后被阻止,那么你的服务器如何成为并发服务器?)
(或者对于第一个版本,我建议您避免这样做,而是在调用SIGINT、的信号处理程序之后使用
signal(SIGCHLD, SIG_IGN); //This should automatically get rid of zombies.
(请在您的系统中进行实验)
链接供参考-http://en.wikipedia.org/wiki/SIGCHLD
4) 您对SIGINT处理程序的论点似乎也不正确。合适的原型是
void (*signal(int sig, void (*func)(int)))(int);
但你的管理员是
void sig_handler(const int signo, const int sockd, const int newsockd).
sockd&newsockfd通过了吗
链接
http://pubs.opengroup.org/onlinepubs/009696899/functions/signal.html
我不确定您是如何杀死子进程的。如果子进程还没有处于Zomb状态,您的sign_handler将处理它。可能需要添加更多日志来澄清子进程生命周期的顺序。
关于一个相关的注意事项:我发现我也为一个CTRL+C获得了多个SIGINT。当我检查我的任务管理器时,我实际上有多个挂起的node.js脚本用于这个应用程序。一旦我在任务管理器中终止了它们,我就开始像预期的那样接收单个SIGINT。