我正在尝试使用pipe
,fork
和exec
与C中的外部程序进行互动。我想强制外部程序执行无缓冲的I / O.到目前为止,这是我的代码中的相关代码段:
...
pid = fork();
if (pid == (pid_t) 0)
{
/* child process */
/* make pipe connections to standard streams */
dup2(wpipe[0], STDIN_FILENO);
dup2(rpipe[1], STDOUT_FILENO);
/* close pipe endings */
close(wpipe[0]); close(rpipe[0]);
close(wpipe[1]); close(rpipe[1]);
/* unbuffered I/O */
setvbuf(stdin, NULL, _IONBF, BUFSIZ);
setvbuf(stdout, NULL, _IONBF, BUFSIZ);
if (execl("path/to/some_binary", "path/to/some_binary", (char *) NULL) == -1)
{
fprintf(stderr, "exec failed\n");
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
...
这不起作用,因为流不会在exec
次调用中存活。因此,使用setvbuf
强制无缓冲的I / O不起作用,因为程序映像(some_binary
)创建了自己的stdin和stdout流,并且不使用我调用的流{{1} } 上。
在我的代码中添加setvbuf
次调用后重新构建some_binary
时,该程序可以正常工作。但是如果你对传递给setvbuf
的二进制文件没有任何控制权,怎么办?如何使用例如exec
或cat
之类的unix命令?
答案 0 :(得分:1)
在一般情况下你不能做你想要的事情(在任意可执行文件的execve(2)
之后没有缓冲...)
缓冲由代码完成(例如,通过与libc
相关的一些<stdio.h>
代码完成。代码由程序execve
- ed。
您可能会在setvbuf(stdin, NULL, _IONBF, BUFSIZ);
之后(但在execve
....之前)使用可能会调用main
的LD_PRELOAD tricks。但这只适用于动态链接的可执行文件。
也许在constructor
- ed共享对象的某些初始化函数中使用一些LD_PRELOAD
function attribute可能会有时执行此操作。或者在该共享对象中重新定义printf
,fopen
,....
您评论说:
使用两个管道与子流程进行双向通信。
然后你的方法是错误的。父进程应监视两个管道,可能使用多路复用调用poll(2),然后(根据多路复用的结果)决定读取或写入子进程。实际上,你需要一些event loop:你自己实现一个简单的事件循环 (例如poll
[迭代地多次调用] 循环)或使用一些现有的(请参阅libevent或libev,或某些工具包提供的那个,如GTK或Qt等。 。)
您也可以与select(2)复用,但由于C10K problem
,我建议poll
阅读Advanced Linux Programming ...
,您不会浪费时间另请参阅this answer您的下一个相关问题。
答案 1 :(得分:0)
您可能会尝试暂停任务,然后修改其图像。你可以通过gdb或/ proc文件系统来完成。 特别是,您可以访问通过/ proc文件系统创建的任务的所有fds。
更新:
如果缓冲由glibc完成,只需覆盖glibc中的相关函数,定义自己的函数,将其编译成共享库并加载程序。