多管道不起作用

Multi-pipe does not work

我需要实现这样的 IPC 模式:

runtime data -> filter1 -> filter2 -> output。 (与 data | filter1 | filter2 相同)。

我可以将数据传递给第一个过滤器,但不能传递给第二个过滤器(可能是因为第一个子 stdout fd 未关闭)。如何正确实施这种模式?

P.S。 filter1 和 filter2 只是从标准输入读取并写入标准输出。

我的代码:

int main() {
    int fd1[2];
    pipe(fd1);
    pid_t pid1;

    if ((pid1 = fork()) > 0) {
        char data[] = "Hello world!";

        close(fd1[0]);
        write(fd1[1], data, sizeof(data));
        close(fd1[1]);
        wait(NULL);
        exit(EXIT_SUCCESS);

    } else if (pid1 == 0) {
        int fd2[2];
        pipe(fd2);
        pid_t pid2;

        dup2(fd1[0], STDIN_FILENO);
        dup2(fd2[1], STDOUT_FILENO);
        close(fd1[0]); close(fd1[1]);
        close(fd2[0]); close(fd2[1]);

        if ((pid2 = fork()) > 0) {
            execl("./upcase", "upcase", NULL);
            perror("execl");
            exit(EXIT_FAILURE);
        } else if (pid2 == 0) {
            close(fd1[0]); close(fd1[1]);

            dup2(fd2[0], STDIN_FILENO);
            close(fd2[0]); close(fd2[1]);

            execl("./reverse", "reverse", NULL);
            perror("execl");
            exit(EXIT_FAILURE);
        } else {
            perror("pid2");
            exit(EXIT_FAILURE);
        }

    } else {
        perror("pid1");
        exit(EXIT_FAILURE);
    }

}

您关闭管道的时间过早。通常,在 dup2 中使用它之前先关闭 fd2[0]。当您在第二个分支之前重定向 FILENO_STDOUT 时,第二个过滤器不再访问原始标准输出。

以下代码有效:

int main() {
    int fd1[2];
    pipe(fd1);
    pid_t pid1;

    if ((pid1 = fork()) > 0) {
        char data[] = "Hello world!";

        close(fd1[0]); // OK, will no longer be used
        write(fd1[1], data, sizeof(data));
        close(fd1[1]);
        wait(NULL);
        exit(EXIT_SUCCESS);

    } else if (pid1 == 0) {
        int fd2[2];
        pipe(fd2);
        pid_t pid2;
        close(fd1[1]); // OK, no used from here

        if ((pid2 = fork()) > 0) {
        dup2(fd1[0], STDIN_FILENO);  // redirections for filter1
        dup2(fd2[1], STDOUT_FILENO);
        close(fd1[0]);               // close everything except stdin and stdout
        close(fd2[0]); close(fd2[1]);
            execl("./upcase", "upcase", NULL);
            perror("execl upcase");
            exit(EXIT_FAILURE);
        } else if (pid2 == 0) {
            close(fd1[0]);             // not used here

            dup2(fd2[0], STDIN_FILENO); // redirection for filter2
            close(fd2[0]); close(fd2[1]); // close all what remains

            execl("./reverse", "reverse", NULL);
            perror("execl reverse");
            exit(EXIT_FAILURE);
        } else {
            ...