2

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

我尝试过使用命名管道,但在程序终止之前 stdout 不会显示,并且 stdin 仅适用于第一个输入(然后 cin 为 null )。

我试过使用 /proc/[pid]/fd 但它只能从终端而不是程序写入和读取。

我已经尝试为此编写一个字符设备文件并且它有效,但一次只有一个程序(这需要一次适用于多个程序)。

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

这样做的主要目的是通过 Web 界面查看程序的提要。我确信必须有某种方法可以做到这一点。有什么我以前没有尝试过的吗?

4

1 回答 1

5

这样做的典型方法是:

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

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

许多程序都有命令行选项来改变它们的缓冲行为。例如,即使 stdout 不是终端,grep(1)也有--line-buffered强制它对输出进行行缓冲的标志。如果您的外部程序有这样的选项,您可能应该使用它。如果没有,仍然可以更改缓冲行为,但您必须使用一些鬼鬼祟祟的技巧——请参阅这个问题这个问题以了解如何做到这一点。

于 2013-03-20T05:43:39.243 回答