【问题标题】:C pipe not functioning with large writesC 管道无法处理大量写入
【发布时间】:2016-04-12 06:33:34
【问题描述】:

使用fork()exec() 和管道编写了一个小脚本来处理php5-cgi。当php5-cgi 的输出很小时,下面的脚本运行良好。但是当它相当大时(在输入文件中使用<?php phpinfo(); ?> 时),它不会返回任何内容。

#include<netinet/in.h>
#include<stdio.h>
#include<stdlib.h>
#include<sys/socket.h>
#include<sys/stat.h>
#include<sys/types.h>
#include<unistd.h>
#include<fcntl.h>

int main(int argc, char const *argv[]) {

  int status;
  int link[2];
  char out[4096];
  char * arg[3]={"php5-cgi","a.php",0};
  if (pipe(link)==-1){
    perror("pipe");
  }
  int pid=fork();
  if (!pid){
    dup2 (link[1], 1);
    close(link[0]);
    execvp("php5-cgi", arg);
  } else {
    waitpid(pid, &status,0);
    close(link[1]); // parent doesn't write
        char reading_buf[1];
        while(read(link[0], reading_buf, 1) > 0){
            write(1, reading_buf, 1);
        }
        close(link[0]);
  }
  printf("%s\n", "end");
  return 0;
}

我认为这是由于管道溢出造成的。我有什么办法可以解决这个问题吗?或者有没有其他方法可以处理大输出?

【问题讨论】:

  • 将你写入的数据拆分成更小的块?
  • 始终要做的第一件事:检查所有系统调用的返回值。

标签: c pipe


【解决方案1】:

管道缓冲区相对较小,通常为几KB。孩子可以写入它,直到缓冲区已满;然后进一步的写入将被阻塞,直到一些数据被读取。

您的父级在尝试从管道读取之前调用waitpid。所以它正在等待孩子终止。但是如果孩子被阻止试图写,它永远不会终止。所以在这种情况下你永远不会超过waitpid

您可能想要做的是将waitpid 移动到read/write 循环之后。然后孩子可以在您阅读时继续写入更多数据。当read() 最终失败时,很可能是因为孩子已经退出并关闭了管道的末端。所以到时候可以waitpid获取退出状态,收割丧尸。

另外,检查所有系统调用的返回值!并在打开警告的情况下进行编译(这会提醒您忘记#include &lt;sys/wait.h&gt;)。

【讨论】:

  • 移动 waitpid 成功了!但这意味着不能保证我会从 exec 获得整个输出到父线程。我说的对吗?
  • @paarandika:不,不正确。您将获得整个输出。为什么你认为你不会?父级中的read 将从管道缓冲区中读取,但如果它变为空,read 将阻塞,直到子级写入更多内容。但是,如果缓冲区为空且子进程已关闭管道或退出,read 将停止阻塞并返回 0。因此,直到子进程写入的所有数据都被读取后,您的循环才会终止。
  • 我认为一旦管道为空,即使孩子没有关闭管道,读取也会返回。顺便说一句,在子进程结束时,管道会自动关闭吗?因为在我的代码中我没有机会关闭它。
  • @paarandika:“我认为一旦管道为空,即使孩子没有关闭管道,读取也会返回。”好吧,这不是真的,除非您在非阻塞模式下打开它(即使这样,它也会返回 -1 且 errno = EAGAIN;read 仅在管道关闭时返回 0)。是的,当子进程退出时,所有打开的文件(包括管道)都将关闭。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-02-28
  • 2013-03-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多