子进程和父进程之间通过管道进行交互双向通信

3
我想创建一个子进程,将其标准输入和输出重定向到父进程,并与子进程进行交互。也就是说,父进程应该能够从子进程接收输入,处理它,并向子进程提供输出,这个循环不断重复(就像用户与shell进行交互一样,这实际上是最终目标:模拟用户交互)。
到目前为止,我已经成功地创建并重定向了管道(下面的代码只是从子进程通过用户在父进程中输入的方式回显输入)。问题是,我只能这样做一次,子进程在第一次I/O周期后终止,并且我会得到一个SIGPIPE信号。如何保持子进程处于活动状态,并使其在父进程写入时读取管道?
附言:我知道可以使用except来模拟用户交互,但我需要访问返回的数据以进行自定义分析,并且出于学术目的,我想这样做。
#include <iostream>
#include <string>
#include <sstream>
#include <unistd.h>
#include <stdio.h>
#include <sys/wait.h>
#include <limits.h>
#include <sys/types.h>
#include <cstdlib>


#define MAX_CMD_SIZE 256
#define MAX_BUFF_SIZE 512

#define NUM_PIPES 2
#define PARENT_READ_PIPE pipes[0]
#define PARENT_WRITE_PIPE pipes[1]

#define READ_END 0
#define WRITE_END 1

#define PARENT_READ_FD PARENT_READ_PIPE[READ_END]
#define PARENT_WRITE_FD PARENT_WRITE_PIPE[WRITE_END]

#define CHILD_READ_FD PARENT_WRITE_PIPE[READ_END]
#define CHILD_WRITE_FD PARENT_READ_PIPE[WRITE_END]

int pipes[NUM_PIPES][2];


int main()
{
    pipe(PARENT_READ_PIPE);
    pipe(PARENT_WRITE_PIPE);

    pid_t process_id = fork();

    if (process_id<0) //throw diag::DiagError("ERROR: error during fork()");
    {std::cerr<<"ERROR: error during fork()"; exit(1);}
    else if (process_id==0)
    {//CHILD process
        dup2(CHILD_READ_FD, STDIN_FILENO);
        dup2(CHILD_WRITE_FD, STDOUT_FILENO);

        close(CHILD_READ_FD);
        close(CHILD_WRITE_FD);
        close(PARENT_READ_FD);
        close(PARENT_WRITE_FD);

        char buffer[MAX_BUFF_SIZE];
        int count = read(STDIN_FILENO, buffer, MAX_BUFF_SIZE-1);
        if (count >= 0) 
        {
            buffer[count] = 0;
            printf("%s", buffer);
        } 
        else //{throw diag::DiagError("IO Error");}
        {std::cerr<<"ERROR: error during fork()"; exit(1);}
        exit(0);
    }
    else
    {//PARENT process
       close(CHILD_READ_FD);
        close(CHILD_WRITE_FD);

        char buffer[MAX_BUFF_SIZE];

        std::string temp="";

        while(std::getline(std::cin,temp))
        {
            write(PARENT_WRITE_FD, temp.c_str(), temp.size());

            //wait(&status);
            int count = read(PARENT_READ_FD, buffer, MAX_BUFF_SIZE-1);
            if (count >= 0) 
            {
                buffer[count] = 0;
                printf("%s", buffer);
            } 
            else //{throw diag::DiagError("IO Error");}
            {std::cerr<<"ERROR: error during fork()"; exit(1);}
        }  
    }
}

抱歉,这段代码是从一个更大的程序中提取出来的...我做了一些修改,现在它可以编译和运行了。 - Ramon
C++和C是不同的编程语言。请不要将C++代码标记为C。 - too honest for this site
2个回答

2

您的子进程在读取一次后退出:

    if (process_id<0) throw diag::DiagError("ERROR: error during fork()");
    else if (process_id==0)
    {//CHILD process
            .....
            exit(0); /* <-- here */
    }

当然,这会导致管道关闭,而你的父进程在试图写入不再读取的管道时会收到 SIGPIPE 信号。 你的父进程代码使用循环来读取/写入子进程 - 在你的子进程代码中也要做相似的事情 - 运行循环而不是退出。 你还可以使用一些特殊的字符串,在子进程中退出循环并终止。

此外,如果您想使用标准输入和输出进行读/写操作,则可以在使用 dup2 复制描述符并关闭正确的管道端点之后调用 exec()。在子进程中,您可以使用普通的 C++ 流,比如 std::cin 和 std::cout。当然,这需要将您的子进程代码重构为一个独立的程序。


是的,我知道这就是为什么它现在失败的原因。如果我只是循环子进程的I/O部分(即 while(true) { /* read and output */ }),它不起作用 - 我看不到子进程的输出。父进程等待用户按下回车键,我怎样才能将类似的东西传递给子进程呢?当它只是循环并尝试从空管道中读取时,我不太确定子进程正在发生什么。也许检查管道是否为空,在这种情况下什么也不做?无论哪种情况,必须有一种方法只在父进程写入时才进行读取。也许可以使用信号? - Ramon
你尝试过调试它吗? - sirgeorge
是的,它缺少了一些调试,谢谢。我意识到我尝试做的事情在根本上有些问题。 - Ramon

0

pollselect家族监视文件描述符,并等待它们准备好进行I/O操作。

最终我使用伪终端进行双向通信,但它们也可以与管道一起使用。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接