【问题标题】:Bi-directional inter-process communication using two pipes使用两个管道进行双向进程间通信
【发布时间】:2013-12-31 05:49:09
【问题描述】:

我正在尝试编写分叉子进程并使用管道与其通信的代码。我正在使用两个管道 - 一个用于写入,另一个用于从子进程的标准流中读取。到目前为止,这是我所拥有的:

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

void read_move(int fd)
{
    FILE *stream = fdopen(fd, "r");
    char c;
    setvbuf(stream, NULL, _IONBF, BUFSIZ);  
    while ((c = fgetc(stream)) != EOF)
    {
        putchar(c);
    }
    fclose(stream);
}

void write_move(int fd, const char *move)
{
    FILE *stream = fdopen(fd, "w");
    setvbuf(stream, NULL, _IONBF, BUFSIZ);
    fprintf(stream, "%s", move);
    fclose(stream);
}

int main() {
    pid_t pid;
    int wpipe[2];
    int rpipe[2];
    if (pipe(wpipe) || pipe(rpipe))
    {
        fprintf(stderr, "Pipe creation failed.\n");
        return EXIT_FAILURE;
    }
    pid = fork();
    if (pid == 0)
    {
        /* gnuchess process */
        setvbuf(stdin, NULL, _IONBF, BUFSIZ);
        setvbuf(stdout, NULL, _IONBF, BUFSIZ);
        setvbuf(stderr, NULL, _IONBF, BUFSIZ);
        dup2(wpipe[0], STDIN_FILENO);
        dup2(rpipe[1], STDOUT_FILENO);
        dup2(rpipe[1], STDERR_FILENO);
        close(wpipe[0]);
        close(wpipe[1]);
        close(rpipe[0]);
        close(rpipe[1]);
        if (execl("/usr/games/gnuchess", "gnuchess", "-x", NULL) == -1)
        {
            fprintf(stderr, "Exec failed.\n");
            return EXIT_FAILURE;
        }
        return EXIT_SUCCESS;
    }

    /* parent process */

    printf("Sending move to GNU Chess... \n");
    close(wpipe[0]); /* Close other end */
    write_move(wpipe[1], "c3\n");   

    printf("Reading response... \n");
    close(rpipe[1]); /* Close other end */
    read_move(rpipe[0]);

    /* clean up */  
    close(wpipe[1]);
    close(rpipe[0]);    

    /* kill gnuchess */
    kill(pid, SIGTERM);

    return EXIT_SUCCESS;
}

上述程序的输出是

Sending move to GNU Chess... 
Reading response... 

它卡在read_move 函数中的getline 调用处,等待输入。但我不明白这怎么可能,因为我已经关闭了另一端。

我做错了什么?

编辑: 我更改了read_move 方法,并在dup2 调用后关闭了子进程中的管道端。

【问题讨论】:

    标签: c subprocess fork pipe inter-process-communicat


    【解决方案1】:

    您没有在子进程中关闭 wpipe。因此,当您启动它时,您实际上将 7 个文件描述符传递给 gnu chess - 复制的标准输入、标准输出和标准错误; wpipe中的2个描述符,rpipe中的2个描述符。

    如果您使用的是 linux,请在程序运行时找出 gnu chess 的进程 ID,然后执行 ls /proc//fd 以查看其所有文件描述符。

    添加后

    关闭(wpipe[0]); 关闭(wpipe[1]); 关闭(rpipe[0]); 关闭(rpipe[1]);

    在 dup2()s 和 execl() 之间,应该没问题。

    (这仍然省略了错误处理,例如其中一个 dup2() 失败的情况,或者更糟糕的是,您的程序在调用 pipe() 之前关闭了 fds [0, 1, 2] 之一的标准描述符被意外替换为管道。但我想这不是重点。)

    【讨论】:

    • 非常感谢您指出这一点。它确实有 7 个文件描述符。但是,在我关闭 4 个管道末端后, ls /proc/PID/fd 仍然给了我 4 个 FD - 0 1 2 3。FD 3 为青色,其他为红色。这是什么意思?
    • 另外,关闭管道末端并不能完全解决问题 - 程序进入无限循环。子进程不断从管道的末端一遍又一遍地读取相同的内容——尽管我只写了一次。
    • 这可能是因为 gnuchess 不能很好地处理 EOF。试试猫 | gnuchess,然后按 ^D - gnuchess 只是忽略 EOF 而不是退出。如果您对 /proc/PID/fd 执行 ls -l,您将获得有关哪个 fd 连接到什么的更多信息。
    猜你喜欢
    • 2011-10-16
    • 1970-01-01
    • 1970-01-01
    • 2017-09-10
    • 2015-09-27
    • 1970-01-01
    • 2018-05-26
    • 1970-01-01
    相关资源
    最近更新 更多