【问题标题】:Trouble establishing pipe communication between python and cpp在 python 和 cpp 之间建立管道通信时遇到问题
【发布时间】:2021-11-27 00:03:44
【问题描述】:

附加的第一段代码是我使用的python 代码(在“test.py”中)。第二个是 c++ 代码(在我编译为“test.out”的“test.cpp”中)。我正在使用 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]收到的消息:


【问题讨论】:

    标签: python c++ pipe cross-platform


    【解决方案1】:

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

    我将文件描述符设置为可继承,当我将它们传递给子进程时,我确保它们没有关闭(正如@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++]收到的消息:message

    [c++]完成

    [Py]收到消息:返回消息


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

    【讨论】:

      【解决方案2】:

      您的 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)
      #                                                                         ^^^^^^^^^^^^^^^
      

      【讨论】:

      • 我听从了您的建议,确实成功了。正如您所提到的,文件描述符没有被继承,我什至没有考虑过(由于我对进程通信缺乏了解)。再一次,正如你提到的,我正在阅读超出范围,这是另一个问题(我通过使用字符数组的长度来修复它,作为消息的长度)。现在我可以在此基础上做一些更复杂的事情。谢谢你,好先生!
      • @MarkosOthonos 太棒了!不客气!
      猜你喜欢
      • 1970-01-01
      • 2019-11-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-06-05
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多