代码之家  ›  专栏  ›  技术社区  ›  Taylor D. Edmiston

popen()可以像pipe()+fork()那样生成双向管道吗?

  •  19
  • Taylor D. Edmiston  · 技术社区  · 14 年前

    pipe() fork() ,和 system() 系统调用,但我更愿意使用 popen() (处理创建管道、分叉进程和向shell传递命令的过程)。这可能是不可能的,因为(我认为)我需要能够从管道的父进程写入,在子进程端读取,从子进程写回输出,最后从父进程读取输出。手册页 波本() 在我的系统中,双向管道是可能的,但我的代码需要在一个旧版本仅支持单向管道的系统上运行。

    波本() ?

    对于一个小例子,运行 ls -l | grep .txt | grep cmds

    • ls -l 在主机上;读回它的输出
    • 管道输出 ls-l型
    • 打开要运行的管道和进程 grep .txt 在主机上的管道输出
    • 通过管道将输出返回到模拟器(卡在这里)
    • 打开要运行的管道和进程 grep cmds 在主机上的管道输出 grep.txt文件

    从Mac OS X:

    这个 波本() 函数“打开”a 通过创建双向 以前打开的任何流 波本() 父进程中的调用已关闭 在新的子进程中。 已实施 带有单向管道;因此, 波本() 允许mode参数指定 阅读或写作,而不是两者兼而有之。因为 现在使用 双向管道,模式参数 可以请求双向数据流。 mode参数是指向 以空结尾的字符串,必须是 “r”代表阅读,“w”代表写作,或 “r+”用于读写。

    5 回复  |  直到 13 年前
        1
  •  11
  •   Jerry Coffin    14 年前

    你好像回答了你自己的问题。如果您的代码需要在不支持 popen 打开双向管道,则无法使用 波本 (至少不是供应的)。

    真正的问题是有关老系统的确切功能。尤其是 pipe 可以创建双向管道,但是 如果没有,那么我将编写要使用的主代码流 波本 使用双向管道,并提供 它可以使用双向管道,在需要时在used中编译。

    如果你需要支持足够老的系统 只支持单向管道 , fork , dup2 等等,你自己。我可能还是用一个有效的函数来包装 几乎 就像现代版的 波本 ,但不是返回一个文件句柄,而是用两个文件句柄填充一个小结构,一个用于子级 stdin ,另一个给孩子的 stdout .

        2
  •  20
  •   salezica    14 年前

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

    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; /* ? */
    }
    

        3
  •  8
  •   Jonathan Leffler    14 年前

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

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

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

    除此之外,任何可移植代码都不会做出任何假设。疯牛病 波本() 类似于你的问题所描述的。

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

        4
  •  2
  •   Community leo1    7 年前

    在其中一个 netresolve stdin 从它的 stdout

    static bool
    start_subprocess(char *const command[], int *pid, int *infd, int *outfd)
    {
        int p1[2], p2[2];
    
        if (!pid || !infd || !outfd)
            return false;
    
        if (pipe(p1) == -1)
            goto err_pipe1;
        if (pipe(p2) == -1)
            goto err_pipe2;
        if ((*pid = fork()) == -1)
            goto err_fork;
    
        if (*pid) {
            /* Parent process. */
            *infd = p1[1];
            *outfd = p2[0];
            close(p1[0]);
            close(p2[1]);
            return true;
        } else {
            /* Child process. */
            dup2(p1[0], 0);
            dup2(p2[1], 1);
            close(p1[0]);
            close(p1[1]);
            close(p2[0]);
            close(p2[1]);
            execvp(*command, command);
            /* Error occured. */
            fprintf(stderr, "error running %s: %s", *command, strerror(errno));
            abort();
        }
    
    err_fork:
        close(p2[1]);
        close(p2[0]);
    err_pipe2:
        close(p1[1]);
        close(p1[0]);
    err_pipe1:
        return false;
    }
    

    https://github.com/crossdistro/netresolve/blob/master/backends/exec.c#L46

    popen simultaneous read and write )

        5
  •  1
  •   Community leo1    7 年前

    不需要在每个进程中创建两个管道和浪费一个文件描述符。用插座代替。 https://stackoverflow.com/a/25177958/894520