C ++双向管道 - 卡在循环中尝试从子进程读取
C++ Bidirectional pipe - stuck trying to read from child process in a loop
我正在尝试创建一个双向管道,让 parent 进程向 child 进程发送消息并等待其答复,对答案做一些事情并发送另一条消息,然后一遍又一遍地重复。
child 进程使用 STDIN 和 STDOUT 接收和发送输入,parent 使用消息作为 c++ strings,所以它们在发送前和接收后进行转换,同样,不同的消息具有不同的(未知)长度。
我写了一个简单的代码来举例说明:
Parent.cpp:
#include <unistd.h>
#include <iostream>
#include <cstring>
#include <string>
int main(){
int parent_to_child[2];
int child_to_parent[2];
pipe(parent_to_child);
pipe(child_to_parent);
int childPID = fork();
if(childPID == 0){
//this is child
close(parent_to_child[1]);//Close the writing end of the incoming pipe
close(child_to_parent[0]);//Close the reading end of the outgoing pipe
dup2(parent_to_child[0], STDIN_FILENO);//replace stdin with incoming pipe
dup2(child_to_parent[1], STDOUT_FILENO);//replace stdout with outgoing pipe
//exec child process
char filename[] = "child.out";
char *newargv[] = { NULL };
char *newenviron[] = { NULL };
execve(filename, newargv, newenviron);
}else{
//this is parent
close(parent_to_child[0]);//Close the reading end of the outgoing pipe.
close(child_to_parent[1]);//Close the writing side of the incoming pipe.
int parent_frame = 0;
char str_to_write[100];
char reading_buffer;
std::string received_str;
do{
//Make the frame number a cstring and append '\n'
strcpy(str_to_write, std::to_string(parent_frame).c_str());
strcat(str_to_write,"\n");
write(parent_to_child[1], str_to_write, strlen(str_to_write));
std::cout << "Parent sent: "<< str_to_write <<std::endl;
received_str = "";
while(read(child_to_parent[0], &reading_buffer, 1) > 0){
received_str += reading_buffer;
}
std::cout << "Parent received: "<< received_str<< std::endl;
} while (++parent_frame);
}
return 0;
}
Child.cpp
#include <unistd.h>
#include <iostream>
int main(){
int child_frame = 0;
char child_buffer[1024];
do{
std::cin >> child_buffer; //wait for father's messages
std::cout << "CHILD received: "<< child_buffer<<" at frame "<< child_frame<<"\n"; //return message to father
}while(++child_frame);
return 0;
}
执行父输出:
Parent sent: 0
...卡住
如果我不创建从 子级到父级 的管道并让父级写入 STDOUT,代码将按预期工作,正如我在终端。因此,表明子级能够从父级读取,但由于某种原因,父级无法从子级读取。
所以我的问题是:为什么父级不能读取子级输出,这是如何工作的?我做错了什么?
问题出在 parent 对最里面 while-loop 内的 read(2)
的调用。
这会持续读取数据,直到 read(2)
returns 值 <= 0。但这只会在 (1) 发生错误或 (2) child 关闭它们时发生写管道的末端。因此 child 发送了它的消息,parent 愉快地阅读了它,然后就坐着等待来自 child 的更多数据。这显然永远不会到来。
问题是您在 while-loop 上的状况。你不想读到 EOF 或错误,你想读整行(如果你使用换行符作为消息定界符)。查看 getline(3)
以使其更容易一些并避免一次读取单个字节,或者 std::getline
如果您将代码变形为更多 C++ 样式。
我正在尝试创建一个双向管道,让 parent 进程向 child 进程发送消息并等待其答复,对答案做一些事情并发送另一条消息,然后一遍又一遍地重复。
child 进程使用 STDIN 和 STDOUT 接收和发送输入,parent 使用消息作为 c++ strings,所以它们在发送前和接收后进行转换,同样,不同的消息具有不同的(未知)长度。
我写了一个简单的代码来举例说明:
Parent.cpp:
#include <unistd.h>
#include <iostream>
#include <cstring>
#include <string>
int main(){
int parent_to_child[2];
int child_to_parent[2];
pipe(parent_to_child);
pipe(child_to_parent);
int childPID = fork();
if(childPID == 0){
//this is child
close(parent_to_child[1]);//Close the writing end of the incoming pipe
close(child_to_parent[0]);//Close the reading end of the outgoing pipe
dup2(parent_to_child[0], STDIN_FILENO);//replace stdin with incoming pipe
dup2(child_to_parent[1], STDOUT_FILENO);//replace stdout with outgoing pipe
//exec child process
char filename[] = "child.out";
char *newargv[] = { NULL };
char *newenviron[] = { NULL };
execve(filename, newargv, newenviron);
}else{
//this is parent
close(parent_to_child[0]);//Close the reading end of the outgoing pipe.
close(child_to_parent[1]);//Close the writing side of the incoming pipe.
int parent_frame = 0;
char str_to_write[100];
char reading_buffer;
std::string received_str;
do{
//Make the frame number a cstring and append '\n'
strcpy(str_to_write, std::to_string(parent_frame).c_str());
strcat(str_to_write,"\n");
write(parent_to_child[1], str_to_write, strlen(str_to_write));
std::cout << "Parent sent: "<< str_to_write <<std::endl;
received_str = "";
while(read(child_to_parent[0], &reading_buffer, 1) > 0){
received_str += reading_buffer;
}
std::cout << "Parent received: "<< received_str<< std::endl;
} while (++parent_frame);
}
return 0;
}
Child.cpp
#include <unistd.h>
#include <iostream>
int main(){
int child_frame = 0;
char child_buffer[1024];
do{
std::cin >> child_buffer; //wait for father's messages
std::cout << "CHILD received: "<< child_buffer<<" at frame "<< child_frame<<"\n"; //return message to father
}while(++child_frame);
return 0;
}
执行父输出:
Parent sent: 0
...卡住
如果我不创建从 子级到父级 的管道并让父级写入 STDOUT,代码将按预期工作,正如我在终端。因此,表明子级能够从父级读取,但由于某种原因,父级无法从子级读取。
所以我的问题是:为什么父级不能读取子级输出,这是如何工作的?我做错了什么?
问题出在 parent 对最里面 while-loop 内的 read(2)
的调用。
这会持续读取数据,直到 read(2)
returns 值 <= 0。但这只会在 (1) 发生错误或 (2) child 关闭它们时发生写管道的末端。因此 child 发送了它的消息,parent 愉快地阅读了它,然后就坐着等待来自 child 的更多数据。这显然永远不会到来。
问题是您在 while-loop 上的状况。你不想读到 EOF 或错误,你想读整行(如果你使用换行符作为消息定界符)。查看 getline(3)
以使其更容易一些并避免一次读取单个字节,或者 std::getline
如果您将代码变形为更多 C++ 样式。