从 Python 子进程中的标准输入读取在 C++/Python IPC 中挂起
Reading from stdin in Python subprocess hangs in C++/Python IPC
我正在开发一个 C++ 应用程序,它启动一个 Python 子进程并尝试在父进程 (C++) 和子进程 (Python) 之间建立通信。特别是,我正在编写 Python 部分,以便与我未编写且无法更改的 C++ 应用程序集成。我已经实现了一个套接字解决方案来处理通信,但我还需要支持使用管道的通信。
我的问题是我可以从 Python 写入 stdout 并且 C++ 应用程序接收到该消息。但是 Python 子进程无法读取父进程发送的消息。我试图推断代码中我认为与描述问题最相关的部分:
C++
void startSubprocess(char* program, char** arguments)
{
int p_stdout;
int p_stdin;
int p_stderr;
int out[2];
int in[2];
int err[2];
char** arguments;
char* program;
pipe(out);
pipe(in);
pipe(err);
posix_spawn_file_actions_init(&action);
posix_spawn_file_actions_addclose(&action, out[1]);
posix_spawn_file_actions_addclose(&action, in[0]);
posix_spawn_file_actions_addclose(&action, err[0]);
posix_spawn_file_actions_adddup2(&action, out[0], 0);
posix_spawn_file_actions_adddup2(&action, in[1], 1);
posix_spawn_file_actions_adddup2(&action, err[1], 2);
std::vector<char *> vars_c(vars.size() + 1);
for (std::size_t i = 0; i != vars.size(); ++i) {
vars_c[i] = &vars[i][0];
}
vars_c[vars.size()] = NULL;
string cwd = __getcwd();
if (directory.size() > 0)
chdir(directory.c_str());
if (posix_spawnp(&pid, program, &action, NULL, arguments, vars_c.data())) {
cleanup();
pid = 0;
if (directory.size() > 0) chdir(cwd.c_str());
return false;
}
if (directory.size() > 0) chdir(cwd.c_str());
p_stdin = out[1];
p_stdout = in[0];
p_stderr = err[0];
}
void write(const char* buf, int len)
{
write(p_stdout, buf, len);
}
void read(char* buf, int len)
{
read(p_stdin, buf, len);
}
Python
def writeMsg(msg):
sys.stdout.write(msg)
sys.stdout.flush()
def readMsg():
msg = sys.stdin.read()
当我 运行 应用程序的父进程 (C++) 读取 Python 子进程发送的消息时。之后 Python 子进程无法从 sys.stdin 读取。它永远等到超时。
当我 运行 C++ 应用程序时,我可以看到 out = [3,4] 和 in=[5,6] 所以 p_stdin=6 和 p_stdout=3 .我正在 Ubuntu 14.04 中测试应用程序。
我一直在尝试其他几种方法(使用 os.fdopen 和 os.read)但没有成功。欢迎任何解决此问题的建议。谢谢!
编辑
我发现我跳过了一些重要的信息来理解这个问题。主应用程序和Python子进程需要不断地通信和读写消息,循环发送和接收,直到终止。代码看起来像这样(仅用于描述目的):
C++
int communicate()
{
// skip var init etc
// launch subprocess
startSubprocess(program, arguments);
while(1)
{
// read message sent by subprocess
read(msg, len);
if(msg == "quit")
break;
// part of the code that generates msg2
// send a message to subproc
write(msg2, len2);
}
return 1;
}
Python
def communicate():
while True:
# generate msg to send to C++
writeMsg(msg)
msgRcv = readMsg()
if msgRcv == 'quit':
break
return
我发现 sys.stdin.read() 在返回消息之前挂起直到 EOF。通过将 msg = sys.stdin.read() 替换为
msg = sys.stdin.readline()
我的应用程序按预期运行。应用程序发送的消息由换行符“\n”分隔,因此这种方法对我有用。在其他情况下,我认为使用
一次读取一个字符
msg += sys.stdin.read(1)
将避免程序在等待 EOF 时挂起。
关于 read 和 readline 之间的区别,已经有几个答案。不幸的是,在我尝试 readline 的测试期间,客户端在读取之前被父进程终止。
我正在开发一个 C++ 应用程序,它启动一个 Python 子进程并尝试在父进程 (C++) 和子进程 (Python) 之间建立通信。特别是,我正在编写 Python 部分,以便与我未编写且无法更改的 C++ 应用程序集成。我已经实现了一个套接字解决方案来处理通信,但我还需要支持使用管道的通信。
我的问题是我可以从 Python 写入 stdout 并且 C++ 应用程序接收到该消息。但是 Python 子进程无法读取父进程发送的消息。我试图推断代码中我认为与描述问题最相关的部分:
C++
void startSubprocess(char* program, char** arguments)
{
int p_stdout;
int p_stdin;
int p_stderr;
int out[2];
int in[2];
int err[2];
char** arguments;
char* program;
pipe(out);
pipe(in);
pipe(err);
posix_spawn_file_actions_init(&action);
posix_spawn_file_actions_addclose(&action, out[1]);
posix_spawn_file_actions_addclose(&action, in[0]);
posix_spawn_file_actions_addclose(&action, err[0]);
posix_spawn_file_actions_adddup2(&action, out[0], 0);
posix_spawn_file_actions_adddup2(&action, in[1], 1);
posix_spawn_file_actions_adddup2(&action, err[1], 2);
std::vector<char *> vars_c(vars.size() + 1);
for (std::size_t i = 0; i != vars.size(); ++i) {
vars_c[i] = &vars[i][0];
}
vars_c[vars.size()] = NULL;
string cwd = __getcwd();
if (directory.size() > 0)
chdir(directory.c_str());
if (posix_spawnp(&pid, program, &action, NULL, arguments, vars_c.data())) {
cleanup();
pid = 0;
if (directory.size() > 0) chdir(cwd.c_str());
return false;
}
if (directory.size() > 0) chdir(cwd.c_str());
p_stdin = out[1];
p_stdout = in[0];
p_stderr = err[0];
}
void write(const char* buf, int len)
{
write(p_stdout, buf, len);
}
void read(char* buf, int len)
{
read(p_stdin, buf, len);
}
Python
def writeMsg(msg):
sys.stdout.write(msg)
sys.stdout.flush()
def readMsg():
msg = sys.stdin.read()
当我 运行 应用程序的父进程 (C++) 读取 Python 子进程发送的消息时。之后 Python 子进程无法从 sys.stdin 读取。它永远等到超时。
当我 运行 C++ 应用程序时,我可以看到 out = [3,4] 和 in=[5,6] 所以 p_stdin=6 和 p_stdout=3 .我正在 Ubuntu 14.04 中测试应用程序。
我一直在尝试其他几种方法(使用 os.fdopen 和 os.read)但没有成功。欢迎任何解决此问题的建议。谢谢!
编辑
我发现我跳过了一些重要的信息来理解这个问题。主应用程序和Python子进程需要不断地通信和读写消息,循环发送和接收,直到终止。代码看起来像这样(仅用于描述目的):
C++
int communicate()
{
// skip var init etc
// launch subprocess
startSubprocess(program, arguments);
while(1)
{
// read message sent by subprocess
read(msg, len);
if(msg == "quit")
break;
// part of the code that generates msg2
// send a message to subproc
write(msg2, len2);
}
return 1;
}
Python
def communicate():
while True:
# generate msg to send to C++
writeMsg(msg)
msgRcv = readMsg()
if msgRcv == 'quit':
break
return
我发现 sys.stdin.read() 在返回消息之前挂起直到 EOF。通过将 msg = sys.stdin.read() 替换为
msg = sys.stdin.readline()
我的应用程序按预期运行。应用程序发送的消息由换行符“\n”分隔,因此这种方法对我有用。在其他情况下,我认为使用
一次读取一个字符msg += sys.stdin.read(1)
将避免程序在等待 EOF 时挂起。
关于 read 和 readline 之间的区别,已经有几个答案。不幸的是,在我尝试 readline 的测试期间,客户端在读取之前被父进程终止。