【发布时间】:2013-07-30 16:50:05
【问题描述】:
我正在尝试用 C 语言编写一个简单的控制台程序,它分叉、运行一个子进程,并使用 pipe() 读取父程序的所有标准输入并将其发送到子程序的标准输入并读取所有标准输出子程序并将其发送到父程序的标准输出。最终,我可以让父程序做一些事情,而不仅仅是传递这些数据——现在,如果父程序的行为就像子程序直接运行一样就足够了。
似乎工作正常,除了当我从子输出管道传输的流中读取()时,它不会返回任何内容,直到遇到换行符。这意味着如果子进程在一行中间提出问题,则直到用户键入答案后,该问题才会出现,这是不可接受的。
我对父母的标准输入也有同样的问题。即使用户应该能够用简单的“y”回答问题,但在用户按下回车之前程序无法读取“y”,这也是不可接受的。
我将输入流设置为非阻塞:
fcntl(stream, F_SETFL, fcntl(stream, F_GETFL) | O_NONBLOCK);
它工作正常,但 read() 返回 -1 直到遇到换行符。
我可以做些什么来从流中读取实际数据而不受部分行的“保护”吗?还是我应该采取一些完全不同的方法?是否有一些开源程序可以做类似的事情,我可以检查一下?
代码在这里:
#include <unistd.h>
#include <sched.h>
#include <fcntl.h>
int main(int argc, const char * const argv[])
{
int outfd[2];
int infd[2];
int oldstdin, oldstdout;
pipe2(outfd, O_NONBLOCK); // Where the parent is going to write to
pipe2(infd, O_NONBLOCK); // From where parent is going to read
oldstdin = dup(0); // Save current stdin
oldstdout = dup(1); // Save stdout
close(0);
close(1);
dup2(outfd[0], 0); // Make the read end of outfd pipe as stdin
dup2(infd[1],1); // Make the write end of infd as stdout
if(!fork())
{
const char * pChildArguments[] = { "/usr/bin/php", "test.php", 0 };
close(outfd[0]); // Not required for the child
close(outfd[1]);
close(infd[0]);
close(infd[1]);
execv(pChildArguments[0], (char * const *)pChildArguments);
}
else
{
char input[100];
close(0); // Restore the original std fds of parent
close(1);
dup2(oldstdin, 0);
dup2(oldstdout, 1);
close(outfd[0]); // These are being used by the child
close(infd[1]);
fcntl(infd[0], F_SETFL, fcntl(infd[0], F_GETFL) | O_NONBLOCK);
fcntl(0, F_SETFL, fcntl(0, F_GETFL) | O_NONBLOCK);
for (;;) {
ssize_t readReturnValue;
readReturnValue = read(infd[0], input, 100);
if (readReturnValue == 0) { break; }
if (readReturnValue > 0) {
write(1, input, readReturnValue);
fsync(1);
}
readReturnValue = read(0, input, 100);
if (readReturnValue > 0) {
write(outfd[1], input, readReturnValue);
fsync(outfd[1]);
}
sched_yield();
}
}
}
改编自this blog post。
test.php(用作子进程)是这样的:
<?php
echo "This lines goes through.\n";
$a = readline("Say something: ");
echo "You said " . $a . "\n";
【问题讨论】:
-
您的孩子会为管道调用 fflush 吗?
-
你确定是接收过程出错,而不是发送方等待换行后再发送吗?您能否编辑您的问题以包含SSCCE,以便我们可以看到您在做什么?
-
我无法控制子进程的编程方式,除了上面的简单测试用例。这个父程序应该适用于任何子程序,并且它的行为应该与子程序直接运行时的行为相同。如果一个问题在child直接运行时正确输出,则应该在parent运行时正确输出。