使用两个管道的双向进程间通信

时间:2013-12-12 17:17:15

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

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

#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... 

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

我做错了什么?

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

1 个答案:

答案 0 :(得分:2)

您没有在子进程中关闭wpipe。所以当你启动它时,你实际上是将7个文件描述符传递给gnu国际象棋 - dup'ed stdin,stdout和stderr; wpipe中的2个描述符,以及rpipe中的2个描述符。

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

添加

接近(wpipe [0]); 关闭(wpipe [1]); 关闭(RPIPE [0]); 关闭(RPIPE [1]);

在dup2()和execl()之间的

,你应该没问题。

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