无法在 python 和 cpp 之间建立管道通信

Trouble establishing pipe communication between python and cpp

附加的第一段代码是我使用的 python 代码(在“test.py”中)。第二个是c++代码(在“test.cpp”中,我编译为“test.out”)。我正在使用 ubuntu (18.04) wsl 来 运行 这些程序。

我首先建立了允许两个进程相互通信的管道。我使用 fork 创建了一个子进程来调用“test.out”,这是 c++ 代码的可执行文件。我将文件描述符作为参数传递给被调用程序。

#Python

import os
import subprocess
import time
#establishing communication pipes
r_sub, w_py = os.pipe()
r_py, w_sub = os.pipe()
#creating a subprocess to run c++ code
pid = os.fork()

if pid > 0:
#Parent
    os.close(r_sub)
    os.close(w_sub)

    print("[Py]Parent process is writing : r_py" + str(r_py) + " w_py" + str(w_py) +  "r_sub" + str(r_sub) + " w_sub" + str(w_sub))
    text = b"message"
    #Writing message to c++ .exe
    os.write(w_py,text)
    print("[Py]Written text:", text.decode())

    os.close(w_py)
    #Reading c++ message
    rec = os.fdopen(r_py)
    print("[Py]Received Message " + rec.read())
else:
    #Child
    print("[SubP]Calling c++ .exe : r_sub" + str(r_sub) + " w_sub" + str(w_sub) + " r_py" + str(r_py) + " w_py" + str(w_py))
    #Calling .exe of c++ code
    subprocess.call(["./test.out",str(r_sub),str(w_sub),str(r_py),str(w_py)])
//c++

#include <iostream>
#include <stdio.h>
#include <unistd.h>
#include <string>
#define MSGSIZE 16

int main(int argc, char *argv[]) {
    if(argc < 5){
        printf("[c++]File descriptors are not present");
        return -1;
    }
    printf("[c++]I received file descriptors: r_sub%s w_sub%s r_py%s w_py%s\n",argv[1],argv[2],argv[3],argv[4]);
    //Arguments are received as character arrays -> turning them to integers to use them as file descriptors
    int r_sub = std::stoi(argv[1]), w_sub = std::stoi(argv[2]), r_py = std::stoi(argv[3]), w_py = std::stoi(argv[4]);
    char buffer[MSGSIZE] = "";

    close(r_py);
    close(w_py);
    //Here I find out that read fails
    if(read(r_sub,buffer,MSGSIZE) == -1)
        printf("\n:(\n");

    printf("[c++]Received message: %s\n",buffer);

    //Attempting to send message back to python
    close(r_sub);
    write(w_sub,"message back",MSGSIZE);
    std::cout << "[c++]Finish\n\n";
    return 0;
}

既没有编译错误也没有“错误的文件描述符”错误,但是通讯不通。实际上,两端都没有收到任何信息。 结果:


python3 test.py

[Py]父进程正在写入:r_py5 w_py4r_sub3 w_sub6

[Py]书面文字:留言

[SubP]调用 c++.exe : r_sub3 w_sub6 r_py5 w_py4

[c++]我收到文件描述符:r_sub3 w_sub6 r_py5 w_py4

:(

[c++]收到的消息:

[c++]完成

[Py]收到消息:


你的 C++ 程序有一些问题(比如 未定义的行为 因为你在 write(w_sub, "message back", MSGSIZE); 中读取你的字符串文字越界)但第一个问题是你的文件描述符不会被启动的程序继承——所以它们在 C++ 程序中都是错误的文件描述符。经常检查 - 不要认为任何事情都是理所当然的。

可以在python中明确设置继承模式:

os.set_inheritable(r_sub, True) # do this for all fds that should be inherited

... 或使用 os.pipe2(0) 打开管道,这使得它们默认可继承。

并确保在您启动子流程时它们没有全部关闭:

subprocess.call(["./test.out",str(r_sub),str(w_sub),str(r_py),str(w_py)], close_fds=False)
#                                                                         ^^^^^^^^^^^^^^^

对于任何想知道更正版本是什么的人:

我将文件描述符设置为可继承,当我将它们传递给子进程时,我确保它们没有关闭(正如@Ted Lyngmo 提到的那样)。在 C++ 中,我将写入长度设置为消息的长度以避免读取越界。

#Python

import os
import subprocess
import time
#establishing communication pipes
r_sub, w_py = os.pipe()
r_py, w_sub = os.pipe()
#creating a subprocess to run c++ code
pid = os.fork()
os.set_inheritable(r_sub, True)
os.set_inheritable(w_sub, True)
os.set_inheritable(r_py, True)
os.set_inheritable(w_py, True)

if pid > 0:
#Parent
    os.close(r_sub)
    os.close(w_sub)

    print("[Py]Parent process is writing : r_py" + str(r_py) + " w_py" + str(w_py) +  "r_sub" + str(r_sub) + " w_sub" + str(w_sub))
    text = b"message"
    #Writing message to c++ .exe
    os.write(w_py,text)
    print("[Py]Written text:", text.decode())

    os.close(w_py)
    #Reading c++ message
    rec = os.fdopen(r_py)
    print("[Py]Received Message:" + rec.read())
else:
    #Child
    print("[SubP]Calling c++ .exe : r_sub" + str(r_sub) + " w_sub" + str(w_sub) + " r_py" + str(r_py) + " w_py" + str(w_py))
    #Calling .exe of c++ code
    subprocess.call(["./test.out",str(r_sub),str(w_sub),str(r_py),str(w_py)], close_fds=False)
//c++

#include <iostream>
#include <stdio.h>
#include <unistd.h>
#include <string>
#define MSGSIZE 16

int main(int argc, char *argv[]) {
    if(argc < 5){
        printf("[c++]File descriptors are not present");
        return -1;
    }
    printf("[c++]I received file descriptors: r_sub%s w_sub%s r_py%s w_py%s\n",argv[1],argv[2],argv[3],argv[4]);
    //Arguments are received as character arrays -> turning them to integers to use them as file descriptors
    int r_sub = std::stoi(argv[1]), w_sub = std::stoi(argv[2]), r_py = std::stoi(argv[3]), w_py = std::stoi(argv[4]);
    char buffer[MSGSIZE] = "";
    char buf[] = "message back";

    close(r_py);
    close(w_py);

    //Attempting to receive message
    if(read(r_sub,buffer,MSGSIZE) == -1)
        printf("\n:(\n");

    printf("[c++]Received message: %s\n",buffer);

    //Attempting to send message back to python
    close(r_sub);
    if(write(w_sub,buf,sizeof(buf)) == -1)
        printf("\n:(\n");
    std::cout << "[c++]Finish\n\n";
    return 0;
}

结果如期而至:


python3 test.py

[Py]父进程正在写入:r_py5 w_py4r_sub3 w_sub6

[Py]书面文字:留言

[SubP]调用 c++.exe : r_sub3 w_sub6 r_py5 w_py4

[c++]我收到文件描述符:r_sub3 w_sub6 r_py5 w_py4

[c++]收到消息:消息

[c++]完成

[Py]收到Message:message返回


再次感谢@Ted Lyngmo swift 对社区的支持!