C管道无法与大型写入一起工作



编写一个小脚本,使用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("%sn", "end");
  return 0;
}

我想这是由于管道溢流造成的。我有办法解决这个问题吗?或者有什么替代方案来处理大额输出吗?

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

您的父级在尝试从管道读取之前调用waitpid。因此,它正在等待孩子终止妊娠。但是,如果孩子在尝试写作时被阻止,它将永远不会终止。因此,在这种情况下,您永远无法通过waitpid

您可能想要做的是将waitpid移动到read/write循环之后。当read()最终失败时,很可能是因为孩子退出并关闭了管道末端。所以你可以在那个时候做waitpid来获得退出状态并收获僵尸。

此外,请检查所有系统调用的返回值!并在打开警告的情况下编译(这将提醒您忘记使用#include <sys/wait.h>)。

最新更新