sigint调用了多次,而不是一次(C)



这是我的代码片段:

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被调用了多次
示例:

  1. 服务器正在侦听
  2. 收到2个连接
  3. 2个儿童叉子
  4. 2个儿童关闭
  5. 现在我想关闭服务器,所以我按下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。

相关内容

最新更新