【问题标题】:Using pipes in C for parent-child IPC makes program block在 C 中使用管道进行父子 IPC 会导致程序阻塞
【发布时间】:2010-10-09 04:52:58
【问题描述】:

我正在编写一个服务器,当它接受套接字连接时,fork() 会关闭子进程。

当子进程与客户端通信时,它必须将部分信息发送回父进程。我正在使用管道来完成此操作。

问题是,当我尝试执行父子 IPC 时,父在读取子输入时会阻塞。这意味着,即使子进程同时运行,它们也只能一次处理一个,因为它们都在等待父进程。

我的代码看起来像这样(为简洁起见,删除了错误检查):

/* loop: wait for clients to connect */
for(;;) {

  pipe(write_to_parent); /* create pipe between parent and child */
  pipe(write_to_child);  /* create pipe between parent and child */

  newsockfd = accept(...);

  pid = fork();

  if (pid == 0) { /* child process */
      close(write_to_parent[0]);
      close(write_to_child[1]);

     printf("Connected!\n");

     while ((rc = recv(newsockfd, ...)) > 0) {
         /* process socket request */

         /* write stuff to parent that is related to what we recv'd from client */
         rc = write(write_to_parent[1], &buf, 1024);
     }

     printf("Disconnected!\n");

     exit(0);
  } else { /* parent */

      close(write_to_parent[1]);
      close(write_to_child[0]);

       while (read(write_to_parent[0], &buf, 1024) > 0) {
           /* accept data from child process, and do some processing */
       }
  }
}

所以我的问题是,我该如何解决这个问题?如何让父母使用管道以不阻塞的方式与孩子进行通信?

这甚至可以通过管道实现,还是我应该使用共享内存(我猜是带有信号量)或消息队列? (我读过这篇文章:Comparing Unix/Linux IPC,但很难找到这些任务是如何实际完成的示例。)

更多细节:

我有一个执行以下操作的测试程序: 1.连接服务器 2. 睡觉(5) 3. 断开与服务器的连接

当我运行这个程序的 2 个实例时,服务器输出如下:

connected!
  // pause for 5 seconds
disconnected!
connected!
  // pause for 5 seconds
disconnected!

显然一次处理一个客户。

当我删除 IPC 时 - 当我从父级和子级中删除管道 read() 和 write() 时,我得到了这个:

connected!
connected!
  // pause for 5ish seconds
disconnected!
disconnected!

这就是我想要的!

有什么想法可以做到这一点吗? (或者我应该在解决这个问题的方式上做出改变?)

(编辑:这是网络课程作业的一部分。我们正在实现一个 P2P 协议,该协议使用集中式服务器来管理对等点。我们可以使用任何语言,我想我会试一试C.)

【问题讨论】:

    标签: c pipe ipc interprocess


    【解决方案1】:

    我在下面写了答案,在重读您的问题后,发现我完全错过了您的实际问题。但是,在任何情况下它都可能是有用的信息。

    要回答您并发的父级问题,您需要让父级设置一个select() 循环,以随时处理来自其任何子级的可能响应。您需要:

    • 跟踪有多少孩子开放
    • 每个孩子保留一组管道
    • 使用带有select() 的循环来接受传入连接(因为它们可能随时发生)以及来自任何子节点的传入数据
    • 使用waitpid()收割已终止的孩子

    此技术功能强大,但需要大量记账才能正确设置。


    在父进程中打开的文件句柄默认在子进程中继承。问题可能是 父母和孩子的管道的写入端仍然打开,所以当父母从管道读取时,它永远不会看到它的结束。在开始阅读 write_to_parent[0] 之前,请尝试在父级中使用 close(write_to_parent[1])。所以:

    } else { /* parent */
         close(write_to_parent[1]);
         while (read(write_to_parent[0], &buf, 1024) > 0) {
             /* accept data from child process, and do some processing */
         }
    }
    

    【讨论】:

    • 您使用 close() 是对的 - 我的代码中有它,但我无意中从这个 sn-p 中省略了它。但是,我已将其添加回来。谢谢!
    猜你喜欢
    • 1970-01-01
    • 2016-06-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多