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

时间:2012-09-05 08:41:07

标签: c fork sigint

这是我的代码片段:

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 connessione\n");
        onexit(newsockd, sockd, 0, 2);
    }
    fprintf(stdout, "Ricevuta richiesta di connessione dall' indirizzo %s\n", 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 x收到连接;
  3. 2 x child fork;
  4. 2个孩子被关闭;
  5. 现在我要关闭服务器,所以我按CTRL + C;
  6. 预期产量:
    received SIGINT, exiting....
    真实输出:
    received SIGINT, exiting....
    received SIGINT, exiting....
    received SIGINT, exiting....

    为什么我有这种行为?

    编辑:代码更新
    当完成1个fork并且孩子完成后我关闭服务器时会发生这种情况:

    ^C7518
    7516
    Received SIGINT, exiting...
    Received SIGINT, exiting...
    

    解决方案:问题是我在指令exit(0) ...代码更新后没有写do_child()

4 个答案:

答案 0 :(得分:2)

信号被发送到当前进程的每个子进程 在您的代码中,当您使用fork时,您将创建一个子进程,该进程从主进程继承SIGINT处理程序。这就是为什么消息被多次打印的原因。

答案 1 :(得分:2)

观察很少,

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。

理想情况下,在创建一个子服务器来为客户端服务之后,主循环应该回到接受状态。 (如果在创建子项后它被阻止了geeting,那么您的服务器如何成为并发服务器?)

(或者对于第一个版本,我建议你在调用SIGINT的信号处理程序之后避免使用它,

signal(SIGCHLD, SIG_IGN);  //This should  automatically get rid of zombies.

(Pl。在您的系统中进行实验)

参考链接 - 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).

sockfd&amp;的价值如何newsockfd正在通过? 链接

http://pubs.opengroup.org/onlinepubs/009696899/functions/signal.html

答案 2 :(得分:0)

我不确定你是如何杀死子进程的。如果子进程还没有处于Zomb状态,你的sign_handler将会对它进行处理。可能需要添加更多日志来阐明子进程生命周期的顺序。

答案 3 :(得分:0)

在相关的说明中:我发现我也为单个CTRL + C获得了多个SIGINT。当我检查我的任务管理器时,我实际上为此应用程序提供了多个挂起的node.js脚本。一旦我在任务管理器中终止它们,我开始按预期接收单个SIGINT。