我正在尝试写stdin并从外部程序中从stdout(和stderr)读取,而无需更改代码。

我尝试使用命名管道,但是直到程序终止并且stdin仅在第一个输入上起作用(然后cin为null)时,stdout才会显示。

我试过使用/proc/[pid]/fd,但这仅从终端而不是从程序进行写入和读取。

我已经尝试为此编写一个字符设备文件,并且该文件可以工作,但是一次只能一个程序(这一次需要为多个程序工作)。

在这一点上,据我所知,我可以编写可在多个程序之间复用io的驱动程序,但我认为这不是“正确的”解决方案。

其主要目的是通过Web界面查看程序的提要。我敢肯定一定有办法做到这一点。有没有我没尝试过的东西?

最佳答案

这样做的典型方法是:

  • 使用 pipe(2) 系统调用为新进程的标准流
  • 创建匿名管道(未命名管道)
  • 调用 fork(2) 生成子进程
  • close(2) 父级和子级中管道的适当末端(例如,对于stdin管道,在父级中关闭读取端,在子级中关闭写入端;对于stdout和stderr管道反之亦然)
  • 在子级中使用 dup2(2) 将管道文件描述符复制到文件描述符0、1和2,然后close(2)其余的旧描述符
  • exec(3) 子进程
  • 中的外部应用程序
  • 在父进程中,同时写入子进程的stdin管道,并从子进程的stdout和stderr管道读取数据。但是,根据 child 的行为,如果不小心,很容易导致死锁。避免死锁的一种方法是生成单独的线程来处理3个流中的每个流。另一种方法是使用 select(2) 系统调用等待,直到可以不阻塞地读取/写入其中一个流,然后处理该流。

  • 即使正确执行了所有操作,您仍然可能不会立即看到程序的输出。这通常是由于缓冲标准输出。通常,当stdout进入终端时,它是行缓冲的—在写入每个换行符后刷新。但是当stdout是管道(或不是终端的任何其他东西,如文件或套接字)时,它将被完全缓冲,并且只有在程序输出了完整缓冲区的数据量(例如4 KB)时才会被写入。

    许多程序都有命令行选项来更改其缓冲行为。例如,grep(1)具有--line-buffered标志,即使标准输出不是终端,也可以强制其对输出进行行缓冲。如果您的外部程序具有这样的选项,则应该使用它。如果没有,仍然可以更改缓冲行为,但是您必须使用一些偷偷摸摸的技巧-有关操作方法,请参见this questionthis question

    09-11 00:37