Piping for input/output

后端 未结 3 674
野趣味
野趣味 2020-12-03 16:13

This question follows from my attempt to implement the instructions in:

Linux Pipes as Input and Output

How to send a simple string between two programs usin

3条回答
  •  猫巷女王i
    2020-12-03 16:29

    Your primary problem is that you have the arguments to dup2() reversed. You need to use:

    dup2(fd_p2c[0], 0);   // Duplicate read end of pipe to standard input
    dup2(fd_pFc[1], 1);   // Duplicate write end of pipe to standard output
    

    I got suckered into misreading what you wrote as OK until I put error checking on the set-up code and got unexpected values from the dup2() calls, which told me what the trouble was. When something goes wrong, insert the error checks you skimped on before.

    You also did not ensure null termination of the data read from the child; this code does.

    Working code (with diagnostics), using cat as the simplest possible 'other command':

    #include 
    #include 
    #include 
    using namespace std;
    
    int main()
    {
        int fd_p2c[2], fd_c2p[2], bytes_read;
        pid_t childpid;
        char readbuffer[80];
        string program_name = "/bin/cat";
        string gulp_command = "this is the command data sent to the child cat (kitten?)";
        string receive_output = "";
    
        if (pipe(fd_p2c) != 0 || pipe(fd_c2p) != 0)
        {
            cerr << "Failed to pipe\n";
            exit(1);
        }
        childpid = fork();
    
        if (childpid < 0)
        {
            cout << "Fork failed" << endl;
            exit(-1);
        }
        else if (childpid == 0)
        {
            if (dup2(fd_p2c[0], 0) != 0 ||
                close(fd_p2c[0]) != 0 ||
                close(fd_p2c[1]) != 0)
            {
                cerr << "Child: failed to set up standard input\n";
                exit(1);
            }
            if (dup2(fd_c2p[1], 1) != 1 ||
                close(fd_c2p[1]) != 0 ||
                close(fd_c2p[0]) != 0)
            {
                cerr << "Child: failed to set up standard output\n";
                exit(1);
            }
    
            execl(program_name.c_str(), program_name.c_str(), (char *) 0);
            cerr << "Failed to execute " << program_name << endl;
            exit(1);
        }
        else
        {
            close(fd_p2c[0]);
            close(fd_c2p[1]);
    
            cout << "Writing to child: <<" << gulp_command << ">>" << endl;
            int nbytes = gulp_command.length();
            if (write(fd_p2c[1], gulp_command.c_str(), nbytes) != nbytes)
            {
                cerr << "Parent: short write to child\n";
                exit(1);
            }
            close(fd_p2c[1]);
    
            while (1)
            {
                bytes_read = read(fd_c2p[0], readbuffer, sizeof(readbuffer)-1);
    
                if (bytes_read <= 0)
                    break;
    
                readbuffer[bytes_read] = '\0';
                receive_output += readbuffer;
            }
            close(fd_c2p[0]);
            cout << "From child: <<" << receive_output << ">>" << endl;
        }
        return 0;
    }
    

    Sample output:

    Writing to child: <>
    From child: <>
    

    Note that you will need to be careful to ensure you don't get deadlocked with your code. If you have a strictly synchronous protocol (so the parent writes a message and reads a response in lock-step), you should be fine, but if the parent is trying to write a message that's too big to fit in the pipe to the child while the child is trying to write a message that's too big to fit in the pipe back to the parent, then each will be blocked writing while waiting for the other to read.

提交回复
热议问题