2

这是我的代码片段:

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 个儿童叉;
  4. 2 x 孩子已关闭;
  5. 现在我想关闭服务器,所以我按 CTRL+C;

预期输出:
received SIGINT, exiting....
真实输出:
received SIGINT, exiting....
received SIGINT, exiting....
received SIGINT, exiting....

为什么我会出现这种行为?

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

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

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

4

4 回答 4

4

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

于 2012-09-05T08:48:11.053 回答
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。

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

(或者对于第一个版本,我建议您在调用 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).

sockfd 和 newsockfd 的值是如何传递的?
关联

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

于 2012-09-05T10:07:32.990 回答
0

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

于 2012-09-05T09:12:59.453 回答
0

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

于 2018-06-14T13:57:41.920 回答