强制使用`exec`创建的程序执行无缓冲的I / O.

我正在尝试使用pipeforkexec与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流,并且不使用我称之为setvbuf的流。

在我的代码中添加setvbuf调用后重新构建some_binary时,该程序可以正常工作。 但是如果你对你传递给exec的二进制文件没有任何控制权,怎么办呢? 如何使用像catls这样的unix命令?

在一般情况下你不能做你想要的(在任意可执行文件的execve(2)之后不缓冲……)

缓冲由代码完成(例如,通过与相关的一些libc代码)。 并且代码由正在执行的程序定义。

你可能会玩LD_PRELOAD技巧 ,可能会调用setvbuf(stdin, NULL, _IONBF, BUFSIZ); 在执行之后 (但在main ……之前); 但这只适用于动态链接的可执行文件。

也许在LD_PRELOAD -ed共享对象的某些初始化函数中使用一些constructor 函数属性 有时可能起作用。 或重新定义printffopen ,….在该共享对象中……

附加物

您评论说:

使用两个管道与子流程进行双向通信。

那你的做法是错的。 父进程应监视两个管道,可能使用poll(2)之类的多路复用调用,然后(根据多路复用的结果)决定读取或写入子进程。 实际上,你需要一些事件循环 :要么自己实现一个简单的事件循环 (例如在重复循环中使用例如poll [迭代地多次调用]),要么使用一些现有循环 (参见libevent或libev ,或某些工具包提供的那个) GTK或Qt等…)

您也可以使用select(2)进行多路复用,但由于C10K问题,我建议使用poll

阅读高级Linux编程,你不会浪费你的时间……

另请参阅下一个相关问题的答案 。

您可以尝试暂停任务,然后修改其图像。 您可以通过gdb或/ proc文件系统来完成。 特别是,您可以访问通过/ proc文件系统创建的任务的所有fds。

更新:

如果缓冲由glibc完成,只需覆盖glibc中的相关函数,通过定义自己的函数,将其编译为共享库并加载程序。