双向 popen() 在 C 中的 Mac OS X 上工作吗?

Gor*_*yle 5 c pipe popen

我的问题 我 在哪里可以找到一个清晰的 C 代码工作示例,该示例在 MacOS 上设置和使用带有 popen() 的双向管道?

我正在尝试使用 popen() 在我的 C 程序和 Mac OS X 上的外部程序之间打开一个双向管道。

我的 C 程序必须反复:

  • 从它自己的标准输入读取输入行
  • 将其重新格式化为外部程序的输入
  • 调用外部程序,将格式化的输入传递给外部程序的标准输入
  • 从外部程序的标准输出读取结果
  • 处理这些结果并在它自己的标准输出上产生一些诊断输出

如果我使用实际文件来存储输入/输出然后使用 system() 或类似文件,我可以轻松地做到这一点,但这太慢了,因为我有数十亿个输入。所以我想完全在内存中完成。

相关的手册页,以及本组和其他人的互联网讨论表明,我可以打开一个通向外部程序的管道,然后像写入文件一样使用 fprintf 写入它。

pout = popen(external_program, "w")
fprintf(pout,input_to_external_program);
Run Code Online (Sandbox Code Playgroud)

这作为一个单向管道工作正常,将格式化的输入输入到外部程序中。

显然,在 Mac OS 上可以通过指定“r+”而不是“r”或“w”作为 popen 的相关参数来打开双向管道,从而使用相同的管道读取和写入程序。

pout = popen(external_program, "r+")
fprintf(pout,"%s", input_to_external_program);
fscanf(fpout,"%s", &output_from_external_program);
Run Code Online (Sandbox Code Playgroud)

我不需要在读、写、读、写等之间交替,因为所有需要发生的是我的程序将在开始读取外部程序的输出之前完成将输入写入外部程序。

外部程序应该只读取一个自包含的输入序列(即它以一个特殊的行结束以指示“输入结束”),然后运行到完成,写入输出,然后终止。

但是当我尝试使用此功能时,它不起作用,因为有些东西阻塞了 - 外部程序启动,但甚至没有完成一个输入。

即使我只是忘记做任何阅读,而只是将“w”替换为“r+”,那么以前工作的功能也会停止工作。

今天早上的大部分时间我都在寻找一个可以修改的工作 popen() 示例,但我发现的所有内容都只使用了单向管道。

所以我们最终回到

我的问题*在哪里可以找到一个清晰的 C 代码工作示例,该示例在 MacOS 上设置和使用带有 popen() 的双向管道?**

如果它更容易,我也许可以用 Perl 替换 C 部分。

更新

感谢您的回答,但我仍然无法使其正常工作,尽管我可以制作一些小规模版本。例如,我编写了一个小程序,它会向输入的任何数字添加一个,如果输入为 -99 则退出/我称之为“复制”。

#include <stdio.h>
#include <unistd.h>

int 
main(int argc, char **argv) {

  int k;

  setbuf(stdout,NULL);

  while (scanf("%d",&k) == 1) {
    if (k == -99) break;
    printf("%d\n",k+1);
  }

}
Run Code Online (Sandbox Code Playgroud)

然后我编写了一个父程序来创建管道,向它写入一些东西,然后等待输出(不做 NOHANG,因为我希望父级继续吸收子级的输出,直到子级完成)。

#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>

int main(void) {

    FILE *p;
    int  k;

    p = popen("copy", "r+");
    if (!p) {
        puts("Can't connect to copy");
        return 1;
    }

    fprintf(p,"%d\n",100);
    fprintf(p,"%d\n",200);
    fprintf(p,"%d\n",300);
    fprintf(p,"%d\n",-99);

    fflush(p);

    while (fscanf(p,"%d",&k) == 1)  {
      printf("%d\n", k);
    }

    pclose(p);

    return 0;
 }
Run Code Online (Sandbox Code Playgroud)

这完美地工作,但是一旦我用我的实际子进程替换虚拟程序“复制”,它就会挂起。

一切都应该是一样的——父进程为子进程创建一个完整的输入序列,它读取它,做一些工作,输出一些任意数量的输出行,然后终止。

但有些事情是不同的 - 要么子进程没有接收到它的所有输入,要么正在缓冲它的输出或其他东西。神秘。

kmk*_*lan 1

确保您fflush(pout)在父进程中并且子进程fflush(stdout)在每次输出后都执行此操作。