0

I have a program that creates a TCP server. When the accept() connects to a client, I fork() it and handle the connection. When that client leaves it calls the waitpid() because of the SIGCHLD, but this causes a EINTR in the accept(). My question is how should this be handled? I've read so many different ways.

Most say to ignore it the EINT and try the accept() again. I've even seen a macro to do just that: TEMP_FAILURE_RETRY(). Some say to set the sigaction flags SA_RESTART and SA_NOCLDSTOP. I've tried that and it introduces other errors (errno = ECHILD). Also, how should the child exit? I've seen both _exit(0) and 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);
      }
   }
}

The SIGCHLD handling is:

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);
}
4

1 回答 1

0

在您的情况下,一个 plainSA_RESTARTwaitpid()in 处理程序可能就足够了。当退出代码无趣时,您可以SA_NOCLDWAIT额外传递。

当客户端出口必须以更复杂的方式处理时,您可以EINTR在主程序中捕获并在waitpid()那里调用。为了让它自由竞争,你应该使用pselect()来阻止信号。或者,您可以创建一个 signalfd 并将其与您的sockfd.

Child 应该使用_exit()来阻止 atexit() 处理程序的执行(例如,将终止条目写入文件)。

于 2015-09-11T19:21:59.477 回答