C++ 输入/输出管道

C++ 输入/输出管道,c++,linux,pipe,C++,Linux,Pipe,这个问题源于我尝试执行中的说明: 我的问题与中的问题大致相同,但更具体 基本上,我试图取代: /directory/program < input.txt > output.txt 因此,我的代码目前使用 system("program < input.txt > output.txt"); system(“程序output.txt”); 我想用管道代替这个过程。我想将我的输入作为标准输入传递给程序,并让我的代码将该程序的标准输出读入字符串。听起来像是您在寻找

这个问题源于我尝试执行中的说明:

我的问题与中的问题大致相同,但更具体

基本上,我试图取代:

/directory/program < input.txt > output.txt
因此,我的代码目前使用

system("program < input.txt > output.txt");
system(“程序output.txt”);

我想用管道代替这个过程。我想将我的输入作为标准输入传递给程序,并让我的代码将该程序的标准输出读入字符串。

听起来像是您在寻找的。您可以用C/C++对它们进行编程,但是由于它们已经在(bash)shell中可用,所以shell的使用更容易,对吗

首先用
coproc
内置程序启动外部程序:

coproc external_program
coproc
在后台启动程序,并将与之通信的文件描述符存储在数组shell变量中。现在,您只需启动程序,将其连接到这些文件描述符:

your_program <&${COPROC[0]} >&${COPROC[1]}
您的_程序&${COPROC[1]}

您的主要问题是
dup2()的参数被颠倒了。您需要使用:

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
我被误导,误读了你写的“OK”,直到我对设置代码进行了错误检查,并从
dup2()
调用中得到了意外值,这告诉了我问题所在。当出现问题时,插入之前略过的错误检查

您也没有确保从子级读取的数据以空终止;这段代码可以

使用
cat
作为最简单的“其他命令”工作代码(带诊断):

#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;
}
#包括
#包括
#包括
使用名称空间std;
int main()
{
int fd_p2c[2],fd_c2p[2],字节读取;
pid_t childpid;
字符读取缓冲区[80];
字符串program_name=“/bin/cat”;
string gulp_command=“这是发送给小猫的命令数据”;
字符串receive_output=“”;
如果(管道(fd|p2c)!=0 |管道(fd|c2p)!=0)
{
cerr
#包括
#包括
#包括
#包括
#包括
#包括
#包括
使用名称空间std;
int main(){
int i,状态,len;
char-str[10];
mknod(“管道”,S|iffo | S|IRUSR | S|IWUSR,0);//创建命名管道
pid_t pid=fork();//创建新进程
/*过程A*/
如果(pid==0){
int myPipe=open(“pipe”,O_WRONLY);//返回管道的文件描述符

cout您的出发点不清楚。您声明要使用管道替换
/directory/program output.txt
,以避免文件系统访问。但您“需要”多个进程才能合理使用管道。(您可以在单个进程中使用管道,但通常没有意义。)因此,您可能有
/directory/program1 output.txt
;这很有意义(您以前可能使用过
/directory/program1 intermediate.txt;/directory/program2 output.txt
)。请澄清你的意图。说得好。我编辑了这个问题。作为额外的澄清,我的目标基本上与你之前回答的:stackoverflow.com/questions/1734932/…中的问题相同(顺便说一句,回答得很好).@Ericinlan如果我想做同样的事情,但只针对两个子进程,我们将如何运行此代码?这意味着在两个子进程之间发送和接收字符串时忽略父进程。@Mohsin我以前从未尝试过这样做。不幸的是,我现在无法给你指导。在我的情况下,我的程序反复调用外部_程序(数千次),每次都有不同的输入。这看起来像是启动时执行的一次性bash脚本,对吗?我对文件描述符不太了解,但如果要使用它,这是否意味着我必须写入驱动器上的文件,或者文件描述符可以指向代码中的字符串?在这种情况下,文件描述符连接到管道,而不是文件。此外,您还可以运行bash脚本数千次。这非常有效。感谢您的帮助,以及对死锁代码的提醒。我认为我不会有这个程序的问题,但知道这一点很好。如果我想做同样的事情,但只为两个子进程,我们将如何运行此代码?意思是发送和接收在忽略父进程的两个子进程之间接收字符串。@Mohsin:这部分取决于子进程将如何通信,以及父进程在启动两个子进程后将执行什么操作。有多种方法可以处理此问题。一种方法是在执行上述任何代码之前简单地使用父进程分支,而父进程或者,父进程设置两个管道,分叉两次,每个子进程整理自己的管道,而父进程关闭这两个管道的四个文件描述符并按自己的方式进行。是的,我做的正是第二种方法按照你的建议,我只是简单地创建一个管道并调用两个fork,一个用于child_a,另一个用于child_b,如果pid_child_a为零,它会写入管道,否则如果pid_child_b为零,它会从缓冲区读取并打印值,问题是当我第一次运行它时,它运行良好,但第二次运行时,它不会打印任何内容e project或再次进行一些编辑会给出正确的输出,但第二次又开始不打印任何内容,以此类推。而且,如果我在调试模式下运行它,每次都会给出正确的输出
your_program <&${COPROC[0]} >&${COPROC[1]}
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
#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;
}
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?)>>
#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;
}