C,' fork:资源暂时不可用'在TCP服务器上

时间:2015-01-25 19:13:09

标签: c fork tcpserver

int
run ()
{
  char str[100];
  int listen_fd, comm_fd;

  struct sockaddr_in servaddr;
  listen_fd = socket (AF_INET, SOCK_STREAM, 0);

  bzero (&servaddr, sizeof (servaddr));
  servaddr.sin_family = AF_INET;
  servaddr.sin_addr.s_addr = htons (INADDR_ANY);
  servaddr.sin_port = htons (8080);
  int n;
  bind (listen_fd, (struct sockaddr *) &servaddr, sizeof (servaddr));
  listen (listen_fd, 10);

  int pid;
  while (1)
    {
      comm_fd = accept (listen_fd, (struct sockaddr *) NULL, NULL);
      if (comm_fd < 0)
        printf ("ERROR on accept");
      //fork new process
      pid = fork ();
      if (pid < 0)
        {
          printf ("ERROR in new process creation");
        }
      if (pid == 0)
        {
          close (listen_fd);
          bzero (str, 256);
          n = read (comm_fd, str, 255);
          if (n < 0)
            printf ("ERROR reading from socket");
          printf ("Here is the message: %s\n", str);
          n = write (comm_fd, "I got your message", 18);
          if (n < 0)
            printf ("ERROR writing to socket");
          close (comm_fd);
        }
      else
        {

          close (comm_fd);
        }
    }

  printf ("readIn Exit!");
  exit (1);

}

为什么这会成为一个二战炸弹,我如何让它作为一个可以处理客户端丢失的多客户端服务器?

有些帖子暗示每个用户的最大进程太低,但我的709.对我来说这件作品似乎很多(我使用的是mac书)

我也尝试了以下方法,但结果相同:

while((comm_fd = accept(listen_fd, (struct sockaddr *) NULL, NULL))){
         pid = fork();
         if(pid == 0){
            close(listen_fd);
            while(1){
              bzero( str, 100);
              read(comm_fd, str, 100);
              printf("S: %s", str);
              write(comm_fd, str, strlen(str)+1);
              sleep(1);
            }
           exit(1);
         } else {
           close(listen_fd);
         }
    }

2 个答案:

答案 0 :(得分:2)

这是一个叉炸弹,因为这部分:

while (1) {
    pid = fork();
    if (pid == 0) { /* child */
       ...read()...write()...
    } else {        /* parent */
       close(comm_fd);
    }
}

这是一个无限循环,其中父级继续分叉和关闭comm_fd。成功读写后,每个孩子将在下一次迭代中进行分叉。重复,直到所有进程槽都泄漏。

您的第二个代码段会耗尽所有流程广告位,因为父级需要wait()wait4()来收集子级的退出状态。在完成此过程之前,进程仍处于僵尸状态。每个僵尸占据一个进程槽。

就像malloc需要相应的免费,fork需要等待。

PS:C中的规范无限循环写为for(;;),以避免while(1)中的常量值布尔值。

答案 1 :(得分:1)

这是一个fork炸弹,因为你永远不会终止这个孩子,所以它继续在accept()给出错误但不终止进程的情况下循环运行。所以它继续fork()并且永远这样做。

修改如下代码:

if (pid == 0)
  {
    close (listen_fd);
    bzero (str, 256);
    n = read (comm_fd, str, 255);
    if (n < 0)
      printf ("ERROR reading from socket");
    printf ("Here is the message: %s\n", str);
    n = write (comm_fd, "I got your message", 18);
    if (n < 0)
      printf ("ERROR writing to socket");
    close (comm_fd);
    exit(some_value); // terminates the child
  }

要清理系统表,您还需要等待终止子项:

else
  {
    close (comm_fd);
    while (waitpid(0,NULL,WNOHANG)!=-1); // clean system tables non blocking
  }

这不是表格的最佳方式,但它相对有效,至少足够。最好的方法是捕获信号SIGCHLD并清理处理程序中的表。