C:如何将命名管道重定向到子进程的标准输入/外部
基本上我想在 C 中(并且没有缓冲)做与这个 bash 脚本相同的事情:
#!/bin/sh
cat ./fifo_in | myprogram > ./fifo_out
换句话说,我想执行“myprogram”并将其 stdin 和 stdout 重定向到之前创建的两个管道。
另一个程序将数据输入 fifo_in 并从 fifo_out 读出。
当然,从 ./fifo_in
读取、在父级中缓冲并写入 myprogram 的标准输入(对于 stdout 和 ./fifo_out
则相反)是很容易的,但我认为可能有一种方法可以让“myprogram”直接从 fifo 读取/写入,而无需在父进程中进行缓冲。
编辑:
尤金的答案似乎是正确的,但我无法让它发挥作用。
我在 C 端使用这个函数,这对我来说似乎是正确的:
pid_t execpipes(const char *wd, const char *command, const char *pipename)
{
char pipename_in[FALK_NAMESIZE];
char pipename_out[FALK_NAMESIZE];
strcpy(pipename_in, FALKPATH);
strcat(pipename_in, "/");
strcat(pipename_in, FALK_FIFO_PATH);
strcat(pipename_in, "/");
strncat(pipename_in, pipename, FALK_NAMESIZE-2);
strcpy(pipename_out, pipename_in);
strcat(pipename_out, "R");
pid_t pid;
pid = fork();
if (pid < 0)
{ //Error occured
perror("fork");
exit(1);
}
if (pid == 0)
{
chdir(wd);
d("execpipes: pipename_in=\"%s\"\n", pipename_in);
d(" pipename_out=\"%s\"\n", pipename_out);
freopen(pipename_in,"r",stdin);
freopen(pipename_out,"w",stdout);
d("execpipes: command=\"%s\"\n", command);
execl("/bin/sh", "sh", "-c", command, (char *)NULL); // using execv is probably faster
// Should never get here
perror("execl");
exit(1);
}
return pid;
}
我从 PHP 脚本读取和写入管道(仅发布相关部分):
$pipe_in = fopen($fp.$pipename, "w");
$DEBUG .= "Write to pipe_in\n";
$ret = fwrite($pipe_in, $in);
$pipe_out = fopen($fp.$pipename.'R', "r");
$DEBUG .= "Read from pipe_out\n";
$atext = fread($pipe_out, 200000); // Program hangs here
程序正确启动,通过 $pipe_in< 接收输入/code> 正确,正确处理数据并且(因为它运行了好几个月)我假设它正确地将数据输出到标准输出,但是当我尝试从
$pipe_out
读取时,它挂起。我知道管道本身设置正确,因为如果我不打开 $pipe_out
,程序不会获得任何输入 - 这是有道理的,因为没有 $pipe_out< 的读取器/code> 因此管道并不完整。所以我可以打开
$pipe_out
,但我无法从中读取任何内容,这很奇怪。
Edit2:
程序现在可以运行了,谢谢大家 - 由于某种原因,第一个管道必须先关闭,然后才能从第二个管道中读取:
$pipe_in = fopen($fp.$pipename, "w");
$pipe_out = fopen($fp.$pipename.'R', "r");
$DEBUG .= "Write to pipe_in\n";
$ret = fwrite($pipe_in, $in);
fclose($pipe_in);
$DEBUG .= "Read from pipe_out\n";
$atext = fread($pipe_out, 200000);
fclose($pipe_out);
unlink($fp.$pipename);
unlink($fp.$pipename.'R');
Basically I want to do in C (and without buffering) the same as this bash-script:
#!/bin/sh
cat ./fifo_in | myprogram > ./fifo_out
In other words I want to exec "myprogram" and redirect its stdin and stdout to two pipes which have been created previously.
Another program is feeding data into fifo_in and reading out of fifo_out.
Of course it would be easy to just read from ./fifo_in
, buffer it in the parent and write to myprogram's stdin (and reverse for stdout and ./fifo_out
) but I think there is probably a way to let "myprogram" read/write directly from/to the fifos without buffering in the parent process.
Edit:
Eugen's answer seems to be the correct one, but I cannot get it to work.
I use this function on the C-side, which seems correct to me:
pid_t execpipes(const char *wd, const char *command, const char *pipename)
{
char pipename_in[FALK_NAMESIZE];
char pipename_out[FALK_NAMESIZE];
strcpy(pipename_in, FALKPATH);
strcat(pipename_in, "/");
strcat(pipename_in, FALK_FIFO_PATH);
strcat(pipename_in, "/");
strncat(pipename_in, pipename, FALK_NAMESIZE-2);
strcpy(pipename_out, pipename_in);
strcat(pipename_out, "R");
pid_t pid;
pid = fork();
if (pid < 0)
{ //Error occured
perror("fork");
exit(1);
}
if (pid == 0)
{
chdir(wd);
d("execpipes: pipename_in=\"%s\"\n", pipename_in);
d(" pipename_out=\"%s\"\n", pipename_out);
freopen(pipename_in,"r",stdin);
freopen(pipename_out,"w",stdout);
d("execpipes: command=\"%s\"\n", command);
execl("/bin/sh", "sh", "-c", command, (char *)NULL); // using execv is probably faster
// Should never get here
perror("execl");
exit(1);
}
return pid;
}
I read and write the pipes from a PHP-script (only relevant part posted):
$pipe_in = fopen($fp.$pipename, "w");
$DEBUG .= "Write to pipe_in\n";
$ret = fwrite($pipe_in, $in);
$pipe_out = fopen($fp.$pipename.'R', "r");
$DEBUG .= "Read from pipe_out\n";
$atext = fread($pipe_out, 200000); // Program hangs here
The program is started correctly, receives the input via $pipe_in
correctly, processes the data correctly and (because it ran fine for many months) I assume it puts out the data correctly to stdout, but when I try to read from $pipe_out
, it hangs. I know that the pipes themselves are set up correctly because if I don't open $pipe_out
, the program does not get any input - which makes sense because there is no reader for $pipe_out
and therefore the pipeline is not complete. So I can open $pipe_out
, but I cannot read anything from it, which is quite strange.
Edit2:
Program works now, thanks guys - For some reason the first pipe has to be closed before you can read from the second pipe:
$pipe_in = fopen($fp.$pipename, "w");
$pipe_out = fopen($fp.$pipename.'R', "r");
$DEBUG .= "Write to pipe_in\n";
$ret = fwrite($pipe_in, $in);
fclose($pipe_in);
$DEBUG .= "Read from pipe_out\n";
$atext = fread($pipe_out, 200000);
fclose($pipe_out);
unlink($fp.$pipename);
unlink($fp.$pipename.'R');
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
我会为 myprogram 编写一个小包装器
(当然不是使用常量路径!),然后 execve myprogram
I'd write a small wrapper for myprogram, that does
(Ofcourse not with constant paths!), then execve myprogram
Korn shell 支持协进程,我认为它可以有效地满足您的要求:从管道读取并写入管道(可以是 C 进程的标准输出和标准输入)
Korn shell supports coprocesses, which I think effectively does what you ask: read from a pipe and write to a pipe (which can be stdout and stdin of a C process)
怎么样
?
至于摆脱缓冲:由于您的程序直接读取/写入管道,因此缓冲不会对您造成伤害。
重要的一点是写入
fifo_in
的进程应该正确刷新,这样您就不必等待。您的输出也是如此:“工作单元”完成后,刷新您的stdout
,这将使数据可供读取输出管道的任何人使用。但是您无法在
myprogram
中执行任何操作来使fifo_in
的编写器刷新其缓冲区。[编辑] 要从 C 语言(无需 shell 的帮助)执行此操作,请使用如下代码:(
简而言之)这就是 shell 在运行命令时所做的事情。确保父进程(
fork()
返回 PID != 0 的进程)处理信号SIGCHLD
How about
?
As for getting rid of the buffering: Since your program directly reads/writes the pipes, the buffering shouldn't hurt you.
An important point is that the process which writes
fifo_in
should flush properly so you don't have to wait. The same goes for your output: As soon as a "work unit" is complete, flush yourstdout
which will make the data available to whoever reads the output pipe.But you can't do anything in
myprogram
to make the writer offifo_in
flush its buffers.[EDIT] To do this from C (without the help of a shell), use code like this:
That's (in a nutshell) what the shell is doing when it runs commands. Make sure the parent process (the one where
fork()
returns a PID != 0) handles the signalSIGCHLD
也许您正在寻找命名管道?例如:
作为 my_program.c 的测试存根,通过缓冲的
stdin
读取fifo_in
:然后作为编写器的测试,使用
bash shell:
注意:
Perhaps you are looking of a named pipe? For example:
As a test stub for my_program.c, to read
fifo_in
via the bufferedstdin
:Then as a test for the writer, using the
bash
shell:Notes: