【问题标题】:C: How to redirect named pipe to stdin/out of child processC:如何将命名管道重定向到标准输入/子进程之外
【发布时间】:2011-12-27 15:58:55
【问题描述】:

基本上我想在 C 中(并且没有缓冲)与这个 bash 脚本一样:

#!/bin/sh
cat ./fifo_in | myprogram > ./fifo_out

换句话说,我想执行“myprogram”并将其标准输入和标准输出重定向到之前创建的两个管道。

另一个程序正在将数据输入 fifo_in 并从 fifo_out 中读出。

当然很容易从./fifo_in 读取,将其缓冲在父程序中并写入myprogram 的标准输入(对于stdout 和./fifo_out 反向),但我认为可能有一种方法可以让“myprogram”直接从/向fifos读取/写入,而不在父进程中缓冲。

编辑:

Eugen 的答案似乎是正确的,但我无法让它发挥作用。

我在 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 正确接收输入,正确处理数据并且(因为它运行了好几个月)我认为它正确地将数据输出到标准输出,但是当我尝试从$pipe_out,挂了。我知道管道本身设置正确,因为如果我不打开$pipe_out,程序不会得到任何输入——这是有道理的,因为$pipe_out 没有阅读器,因此管道不完整。所以我可以打开$pipe_out,但我不能从中读取任何内容,这很奇怪。

编辑2:

程序现在可以运行了,谢谢大家 - 出于某种原因,必须先关闭第一个管道,然后才能从第二个管道读取:

$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');

【问题讨论】:

  • 您是在为myprogram 或其他“调用”myprogram 的程序编写源代码吗?
  • 有什么理由滥用cat?为什么不使用:myprogram &lt; ./fifo_in &gt; ./fifo_out
  • 没有理由使用 cat,bash 脚本只是为了阐明 C 程序应该做什么。

标签: c fifo


【解决方案1】:

我会为我的程序写一个小包装器,确实如此

freopen("./fifo_in","r",stdin)
freopen("./fifo_out","w",stdout)

(当然不是恒定路径!),然后执行 myprogram

【讨论】:

  • 谢谢,我在 C 端使用过这个(见上面的编辑),但是在尝试从 fifo_out 读取时系统挂起。
【解决方案2】:

Korn shell 支持协同进程,我认为它可以有效地满足您的要求:从管道读取并写入管道(可以是 C 进程的标准输出和标准输入)

http://www.dartmouth.edu/~rc/classes/ksh/coprocesses.html

【讨论】:

  • 但是如何从 C 中以编程方式做到这一点?
  • 我认为 OP 想要使用现有的 C 代码并想要一个 shell 包装器。
【解决方案3】:

怎么样

myprogram < ./fifo_in > ./fifo_out

?

关于摆脱缓冲:由于您的程序直接读取/写入管道,因此缓冲不应该伤害您。

重要的一点是写入fifo_in 的进程应该正确刷新,这样您就不必等待。您的输出也是如此:一旦“工作单元”完成,请刷新您的 stdout,这将使读取输出管道的任何人都可以使用数据。

但是你不能在myprogram 中做任何事情来让fifo_in 的写入者刷新它的缓冲区。

[EDIT] 要从 C 中执行此操作(无需 shell 的帮助),请使用如下代码:

- Put the names of the two pipes into local variables on the stack
- Call `fork()`. If that returns '0', then open the two fifos with `freopen()` [like Eugen suggested][1]
- Call `execve` to launch the real exec.

这就是(简而言之)shell 在运行命令时所做的事情。确保父进程(fork() 返回 PID != 0 的那个)处理信号 SIGCHLD

【讨论】:

  • 这就是你在 shell 中的做法。但是 OP 正在询问他如何使用 C 从自己的流程中执行此操作。
【解决方案4】:

也许您正在寻找named pipe?例如:

   mkfifo fifo_in

作为 my_program.c 的测试存根,通过缓冲的 stdin 读取 fifo_in

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

int main(void) {
   char buf[80];
   if (!freopen("./fifo_in", "r", stdin)) {
      perror("freopen");
      exit(EXIT_FAILURE);
   }
   while (!ferror(stdin)) {
      while (fgets(buf, sizeof buf, stdin))
         fputs(buf, stdout);
      sleep(1);
   }
   return 0;
}

然后作为作者的测试,使用bash shell:

for x in {1..10}; do 
   echo $x 
   echo $x >> fifo_in 
   sleep 1 
done

注意事项:

  • 我更喜欢使用无缓冲 I/O。
  • 至少在我的机器上,写入器会阻塞,直到有读取器为止。
  • 在此示例中,阅读器无法判断编写器何时完成。

【讨论】:

    猜你喜欢
    • 2013-07-16
    • 2016-04-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-08-20
    相关资源
    最近更新 更多