如何与另一个外部程序通信程序

时间:2013-03-20 05:28:26

标签: c linux stdio

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

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

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

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

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

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

1 个答案:

答案 0 :(得分:5)

这样做的典型方法是:

  1. 使用pipe(2)系统调用为新进程的标准流创建匿名管道(非命名管道)
  2. 调用fork(2)以生成子进程
  3. close(2)父节点和子节点中管道的适当末端(例如,对于stdin管道,关闭父节点中的读取端并关闭子节点中的写入节点;反之亦然,对于stdout和stderr管道)
  4. 在子代中使用dup2(2)将管道文件描述符复制到文件描述符0,1和2,然后close(2)剩余的旧描述符
  5. exec(3)子进程中的外部应用程序
  6. 在父进程中,同时写入子节点的stdin管道并从子节点的stdout和stderr管道中读取。但是,根据孩子的行为方式,如果你不小心,这很容易导致死锁。避免死锁的一种方法是生成单独的线程来处理3个流中的每一个;另一种方法是使用select(2)系统调用等待,直到可以不受阻塞地读取/写入其中一个流,然后处理该流。
  7. 即使您正确执行此操作,您仍可能无法立即看到程序的输出。这通常是由于缓冲标准输出。通常,当stdout进入终端时,它是行缓冲的 - 它会在每个换行符写入后刷新。但是当stdout是一个管道(或者其他任何不是终端的东西,比如文件或套接字)时,它是完全缓冲的,只有在程序输出完整缓冲区的数据(例如4 KB)时才会被写入。

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