Piping for input/output

后端 未结 3 651
野趣味
野趣味 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条回答
  • 2020-12-03 16:18

    It sounds like you're looking for coprocesses. You can program them in C/C++ but since they are already available in the (bash) shell, easier to use the shell, right?

    First start the external program with the coproc builtin:

    coproc external_program
    

    The coproc starts the program in the background and stores the file descriptors to communicate with it in an array shell variable. Now you just need to start your program connecting it to those file descriptors:

    your_program <&${COPROC[0]} >&${COPROC[1]}
    
    0 讨论(0)
  • 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 <unistd.h>
    #include <string>
    #include <iostream>
    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: <<this is the command data sent to the child cat (kitten?)>>
    From child: <<this is the command data sent to the child cat (kitten?)>>
    

    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.

    0 讨论(0)
  • 2020-12-03 16:34
    #include <stdio.h>
    #include <unistd.h>
    #include <sys/stat.h>
    #include <sys/wait.h>
    #include <fcntl.h>
    #include <string.h>
    #include <iostream>
    using namespace std;
    int main() {
        int i, status, len;
        char str[10];
        mknod("pipe", S_IFIFO | S_IRUSR | S_IWUSR, 0); //create named pipe
        pid_t pid = fork(); // create new process
        /* Process A */
        if (pid == 0) {
            int myPipe = open("pipe", O_WRONLY); // returns a file descriptor for the pipe
            cout << "\nThis is process A having PID= " << getpid(); //Get pid of process A
            cout << "\nEnter the string: ";
            cin >> str;
            len = strlen(str);
            write(myPipe, str, len); //Process A write to the named pipe
            cout << "Process A sent " << str;
            close(myPipe); //closes the file descriptor fields.
            }
        /* Process B */
            else {
            int myPipe = open("pipe", O_RDONLY); //Open the pipe and returns file descriptor
            char buffer[21];
            int pid_child;
            pid_child = wait(&status); //wait until any one child process terminates
            int length = read(myPipe, buffer, 20); //reads up to size bytes from pipe with descriptor fields, store results
        //  in buffer;
            cout<< "\n\nThis is process B having PID= " << getpid();//Get pid of process B
            buffer[length] = '\0';
            cout << "\nProcess B received " << buffer;
            i = 0;
            //Reverse the string
            for (length = length - 1; length >= 0; length--)
            str[i++] = buffer[length];
            str[i] = '\0';
            cout << "\nRevers of string is " << str;
            close(myPipe);
            }
        unlink("pipe");
    return 0;
    }
    
    0 讨论(0)
提交回复
热议问题