Python and C ++ Integration

    Good day to all!

    Recently, when prototyping one of the parts of the product we were developing, one interesting task arose: it was necessary to check the gluing of Python and C ++. This was due to the fact that the main code was written on the pros, and it was necessary to connect an external Websockets library written in Python (at that time there was no corresponding C ++ library). The interaction scheme for such a task is quite simple. The function of connecting to the server (in python) is called from C ++, its address is passed as a parameter. Accordingly, when receiving a message, Python passes it back to the C ++ method.

    When writing the code, the Websocket Python library from Autobahn ( http://www.tavendo.de/autobahn/clientlibraries.html was used), which was necessary to call from C ++. For these purposes, Python provides the Python C-API ( http://docs.python.org/extending/index.html ), however many simple actions, for example, calling functions, are done by several actions. After a little googling, a number of libraries were found to simplify such actions: Boost.Python ( http://www.boost.org/doc/libs/1_39_0/libs/python/doc/index.html ), SWIG ( http: // www.swig.org/ ), Py ++, Pybindgen, Pyrex ... As a result, Boost.Python was chosen as the most popular solution.

    To begin with, we will write a simple echo client in Python, which will send a “Hello world” message to itself once a second, receive it and send it in C ++. cppMethods will be declared in C ++ code,cppMethods.printMessage (msg) - just the place of gluing on the part of Python, directly calling the C ++ function that will print the received message.

    Here is the Python code - echo-client.py :
    from twisted.internet import reactor
    from autobahn.websocket import WebSocketClientFactory, WebSocketClientProtocol, connectWS
    import cppMethods 
    class EchoClientProtocol(WebSocketClientProtocol):
       def sendHello(self):
          self.sendMessage("Hello, world!")  
       def onOpen(self):
          self.sendHello()
       def onMessage(self, msg, binary):
          cppMethods.printMessage(msg)
          reactor.callLater(1, self.sendHello)
    def Connect(addressStr):
        factory = WebSocketClientFactory(addressStr)
        factory.protocol = EchoClientProtocol
        connectWS(factory)
        reactor.run()
    


    Now we write in C ++ code in which we describe our function called from python. To use the Python C-API, you need to include Python.h. Please note that at this point we are not yet using Boost.Python , just the native Python C-API itself .

    PrintEmb.cpp :
    #include 
    #include 
    #include 
    static PyObject * 
    printString(PyObject * self, PyObject* args)
    {
        const char * toPrint;
        if(!PyArg_ParseTuple(args, "s", &toPrint))
        {
            return NULL;
        }
        std::cout << toPrint << std::endl;
        Py_RETURN_NONE;
    }
    static PyMethodDef EmbMethods[] = {
        {"printMessage", printString, METH_VARARGS, "Return the string recieved from websocket server"},
        {NULL, NULL, 0, NULL}
    };
    


    In the last announcement, we described that when calling the printMessage function from Python, the C ++ printString method will be called .

    And finally, we will tie it all together. In addition to the echo client, a link to html5labs was used to test the operation of websockets.

    WebSocketConnect.cpp :
    #include 
    #include 
    #include 
    #include 
    #include "PrintEmb.cpp" 
    void WebSocketConnect()
    {
        using namespace boost::python;
        Py_Initialize();
        Py_InitModule("cppMethods", EmbMethods);
        PyObject * ws = PyImport_ImportModule("echo_client");
        std::string address = "ws://html5labs-interop.cloudapp.net:4502/chat";
        call_method(ws, "Connect", address);
        Py_Finalize();
    }
    

    In this place, we nevertheless took advantage of the capabilities of Boost, namely the call_method function , otherwise we would have needed to write significantly more code.

    Something like that. Here we initialized the EmbMethods for python, calling them cppMethods , and then we called the Connect method from Python and passed the string “address” to it. As a result, our application prints the line “Hello World” (which the python sends to itself) once a second, as well as any message coming from the websocket server.

    This way you can connect Python and C ++. I would be grateful for comments on the topic.

    Upd. Corrected the code in accordance with the comments from the comments.

    Also popular now: