【问题标题】:Proper way of handling SIGCHLD, EINT, and accept() in Linux在 Linux 中处理 SIGCHLD、EINT 和 accept() 的正确方法
【发布时间】:2015-09-11 18:58:51
【问题描述】:

我有一个创建 TCP 服务器的程序。当 accept() 连接到客户端时,我 fork() 它并处理连接。当该客户端离开时,它会因为 SIGCHLD 而调用 waitpid(),但这会导致 accept() 中出现 EINTR。我的问题是应该如何处理?我读过很多不同的方式。

大多数人说忽略它 EINT 并再次尝试 accept()。我什至见过一个宏可以做到这一点:TEMP_FAILURE_RETRY()。有人说要设置 sigaction 标志 SA_RESTART 和 SA_NOCLDSTOP。我已经尝试过了,它引入了其他错误(errno = ECHILD)。另外,孩子应该如何退出? _exit(0) 和 exit(0) 我都见过。

int main( int argc, char *argv[] )
{
   int sockfd, newsockfd, clilen;
   struct sockaddr_in cli_addr;
   int  pid;

   f_SigHandler();
   sockfd = f_SetupTCPSocket();
   clilen = sizeof(cli_addr);

   while (1)
   {
      newsockfd = accept(sockfd, (struct sockaddr *) &cli_addr, &clilen);
      if (newsockfd < 0)
      {
        if( errno == EINTR ) continue;
        else                 exit(1) ;
      }

      pid = fork();
      if (pid == 0)
      {
        close(sockfd);
        doprocessing();
        close(newsockfd);
        _exit(0);
      }
      else
      {
        close(newsockfd);
      }
   }
}

SIGCHLD 处理是:

void f_ChildHandler(int signal_number)
{
  while (waitpid(-1, NULL, WNOHANG) > 0)
  {
  }
}

void f_SigHandler(void)
{
    struct sigaction sa;

    memset(&sa, 0, sizeof(sa));
    sa.sa_handler = f_ChildHandler;
    sigemptyset(&sa.sa_mask);
    sa.sa_flags = 0;
    sigaction(SIGCHLD, &sa, NULL);
}

【问题讨论】:

标签: linux zombie-process sigchld eintr sigaction


【解决方案1】:

在您的情况下,处理程序中的普通 SA_RESTARTwaitpid() 可能就足够了。当退出代码不感兴趣时​​,您可以额外传递SA_NOCLDWAIT

当客户端退出必须以更复杂的方式处理时,您可以在主程序中捕获EINTR并在那里调用waitpid()。为了让它不受干扰,您应该使用pselect() 来阻止信号。或者,您可以创建一个 signalfd 并使用您的 sockfd 在 select/poll 中使用它。

子级应使用_exit() 来防止执行 atexit() 处理程序(例如,将终止条目写入文件)。

【讨论】:

  • 当一个孩子存在并且那个孩子 _exit() 的,f_ChildHandler() 被调用。第一次通过 while 循环 waitpid() 返回刚刚退出的孩子的 pid。第二次,waitpid() 返回 -1 并将 errno 设置为 10 (ECHILD)。我预料到了这一点,因为没有更多的孩子,这就是当没有更多孩子时 waitpid() 应该做的。所以,如果我想运行“无错误”,我是否应该在 f_ChildHandler() 中调用一次 waitpid() 并设置 SA_RESTART?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-10-31
  • 2012-09-30
  • 2012-04-19
  • 1970-01-01
  • 1970-01-01
  • 2010-12-08
相关资源
最近更新 更多