pipe道input/输出

这个问题来自我尝试执行下列指令:

Linuxpipe道作为input和输出

如何使用pipe道在两个程序之间发送一个简单的string?

http://tldp.org/LDP/lpg/node11.html

我的问题是在Linuxpipe道作为input和输出的问题 ,但更具体的。

本质上,我试图取代:

/directory/program < input.txt > output.txt 

在C ++中使用pipe道以避免使用硬盘驱动器。 这是我的代码:

 //LET THE PLUMBING BEGIN int fd_p2c[2], fd_pFc[2], bytes_read; // "p2c" = pipe_to_child, "pFc" = pipe_from_child (see above link) pid_t childpid; char readbuffer[80]; string program_name;// <---- includes program name + full path string gulp_command;// <---- includes my line-by-line stdin for program execution string receive_output = ""; pipe(fd_p2c);//create pipe-to-child pipe(fd_pFc);//create pipe-from-child childpid = fork();//create fork if (childpid < 0) { cout << "Fork failed" << endl; exit(-1); } else if (childpid == 0) { dup2(0,fd_p2c[0]);//close stdout & make read end of p2c into stdout close(fd_p2c[0]);//close read end of p2c close(fd_p2c[1]);//close write end of p2c dup2(1,fd_pFc[1]);//close stdin & make read end of pFc into stdin close(fd_pFc[1]);//close write end of pFc close(fd_pFc[0]);//close read end of pFc //Execute the required program execl(program_name.c_str(),program_name.c_str(),(char *) 0); exit(0); } else { close(fd_p2c[0]);//close read end of p2c close(fd_pFc[1]);//close write end of pFc //"Loop" - send all data to child on write end of p2c write(fd_p2c[1], gulp_command.c_str(), (strlen(gulp_command.c_str()))); close(fd_p2c[1]);//close write end of p2c //Loop - receive all data to child on read end of pFc while (1) { bytes_read = read(fd_pFc[0], readbuffer, sizeof(readbuffer)); if (bytes_read <= 0)//if nothing read from buffer... break;//...break loop receive_output += readbuffer;//append data to string } close(fd_pFc[0]);//close read end of pFc } 

我绝对相信上面的string是正确初始化的。 但是,有两件事情对我来说没有意义:

(1)我正在执行的程序报告“input文件为空”。 由于我不是用“<”来调用程序,所以不应该期待input文件。 相反,它应该是期待键盘input。 此外,它应该阅读“gulp_command”中包含的文本。

(2)程序的报告(通过标准输出提供)出现在terminal中。 这很奇怪,因为这个pipe道的目的是将stdout传递给我的string“receive_output”。 但是由于它出现在屏幕上,这表明信息没有通过pipe道正确传递给variables。 如果我在if语句结尾处执行以下操作,

 cout << receive_output << endl; 

我什么也没得到,好像string是空的。 我感谢您能给我的任何帮助!

编辑:澄清

我的程序当前使用文本文件与另一个程序通信。 我的程序写入一个文本文件(如input.txt),由外部程序读取。 该程序然后产生output.txt,这是我的程序读取。 所以这是这样的:

 my code -> input.txt -> program -> output.txt -> my code 

因此,我的代码目前使用,

 system("program < input.txt > output.txt"); 

我想用pipe道replace这个过程。 我想将我的input作为标准input传递给程序,并让我的代码将该程序的标准输出读入string。

Solutions Collecting From Web of "pipe道input/输出"

你的主要问题是你有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 

我误会了你写错了,直到我把错误检查的设置代码,并从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; } 

示例输出:

 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?)>> 

请注意,您需要小心以确保您的代码不会死锁。 如果你有一个严格的同步协议(所以父母写一个消息,并读锁定步骤的响应),你应该没问题,但如果父母试图写一个消息太大,不适合管到孩子而孩子正在试图写一个太大的消息,使其不能回到父母的管道中,那么每个人都将被阻止写入,同时等待另一个读取。

这听起来像你正在寻找coprocesses 。 你可以用C / C ++编写它们,但由于它们已经在(bash)shell中可用了,所以更容易使用shell,对吗?

首先用coproc builtin启动外部程序:

 coproc external_program 

coproc在后台启动程序,并将文件描述符存储在一个数组shell的变量中。 现在你只需要开始你的程序连接到这些文件描述符:

 your_program <&${COPROC[0]} >&${COPROC[1]} 
 #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; }