首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >popen()能制造像管道()+叉()这样的双向管道吗?

popen()能制造像管道()+叉()这样的双向管道吗?
EN

Stack Overflow用户
提问于 2010-10-07 17:15:53
回答 6查看 17.3K关注 0票数 24

我正在C++中的一个模拟文件系统上实现管道(主要是用C)。它需要在主机外壳中运行命令,但在模拟的文件系统上执行管道本身。

我可以通过pipe()fork()system()系统调用来实现这一点,但我更喜欢使用popen() (它处理创建管道、分叉进程和将命令传递给shell)。这可能是不可能的,因为(我认为)我需要能够从管道的父进程写入,在子进程结束时读取,从子进程写入输出,最后从父进程读取输出。我的系统上的popen()手册页说双向管道是可能的,但是我的代码需要运行在一个只支持单向管道的旧版本的系统上。

与上面的单独调用,我可以打开/关闭管道来实现这一点。对popen()**?**来说,这有可能吗?

对于一个简单的例子,要运行ls -l | grep .txt | grep cmds,我需要:

  • 打开管道和进程,在主机上运行ls -l;将其输出读回
  • ls -l的输出输送回我的模拟器
  • 打开管道并在grep .txt输出的管道上在主机上运行ls -l
  • 把这个输出输回模拟器(卡在这里)
  • 打开管道并在grep cmds输出的管道上在主机上运行grep .txt
  • 将此输出输回模拟器并打印出来。

man popen

来自Mac:

popen()函数通过创建双向管道、分叉和调用shell来“打开”进程。父进程中以前的popen()调用打开的任何流都将在新的子进程中关闭。历史上,popen()是用单向管道实现的;因此,许多popen()实现只允许模式参数指定读或写,而不是两者都指定。因为popen()现在是使用双向管道实现的,所以模式参数可能请求双向数据流。模式参数是指向以空结尾的字符串的指针,该字符串必须为“r”用于读取,“w”用于写入,或“r+”用于读取和写入。

EN

回答 6

Stack Overflow用户

回答已采纳

发布于 2010-10-07 17:32:18

你似乎已经回答了你自己的问题。如果您的代码需要在不支持popen打开双向管道的旧系统上工作,那么您将无法使用popen (至少不能使用所提供的)。

真正的问题是有关较旧系统的确切能力。特别是,他们的pipe是否支持创建双向管道?如果他们有一个可以创建双向管道的pipe,但没有创建双向管道的popen,那么我将编写代码的主要流,以便在双向管道中使用popen,并提供一个popen的实现,该实现可以使用在需要时编译的双向管道。

如果您需要支持足够老的系统,使pipe只支持单向管道,那么您几乎只能自己使用pipeforkdup2等。我可能仍然会把它封装在一个几乎像现代版本的popen的函数中,但是不是返回一个文件句柄,而是用两个文件句柄填充一个小结构,一个用于子文件的stdin,另一个用于子文件的stdout

票数 10
EN

Stack Overflow用户

发布于 2010-10-07 17:55:42

我建议写你自己的函数来帮你做管道/分叉/系统。可以让函数生成一个进程并返回读/写文件描述符,如.

代码语言:javascript
复制
typedef void pfunc_t (int rfd, int wfd);

pid_t pcreate(int fds[2], pfunc_t pfunc) {
    /* Spawn a process from pfunc, returning it's pid. The fds array passed will
     * be filled with two descriptors: fds[0] will read from the child process,
     * and fds[1] will write to it.
     * Similarly, the child process will receive a reading/writing fd set (in
     * that same order) as arguments.
    */
    pid_t pid;
    int pipes[4];

    /* Warning: I'm not handling possible errors in pipe/fork */

    pipe(&pipes[0]); /* Parent read/child write pipe */
    pipe(&pipes[2]); /* Child read/parent write pipe */

    if ((pid = fork()) > 0) {
        /* Parent process */
        fds[0] = pipes[0];
        fds[1] = pipes[3];

        close(pipes[1]);
        close(pipes[2]);

        return pid;

    } else {
        close(pipes[0]);
        close(pipes[3]);

        pfunc(pipes[2], pipes[1]);

        exit(0);
    }

    return -1; /* ? */
}

你可以在里面添加你需要的任何功能。

票数 20
EN

Stack Overflow用户

发布于 2010-10-07 17:29:20

POSIX规定,popen()调用不是为提供双向通信而设计的:

popen()的模式参数是一个指定I/O模式的字符串:

  1. 如果模式为r,则当子进程启动时,其文件描述符STDOUT_FILENO应是管道的可写端,而调用进程中的文件描述符fileno(流),其中流是popen()返回的流指针,将是管道的可读结束。
  2. 如果模式为w,则当子进程启动时,其文件描述符STDIN_FILENO应该是管道的可读端,调用进程中的文件描述符fileno(流),其中流是popen()返回的流指针,应该是管道的可写端。
  3. 如果模式是任何其他值,则结果未指定。

任何可移植代码都不会做出任何假设。BSD popen()类似于您的问题描述的内容。

此外,管道不同于套接字,每个管道文件描述符都是单向的.您必须创建两个管道,一个为每个方向配置。

票数 9
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/3884103

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档