Search code examples
pythonc++czeromqpyzmq

Migrate a "zmq_send" command to Python


I have a c function that publish data to a c++ subscriber, now I want to migrate this c function to Python:

void setup_msg_publish() {
    int r;
    zmqcontext = zmq_ctx_new();
    datasocket = zmq_socket(zmqcontext, ZMQ_PUB);
    r = zmq_bind(datasocket, "tcp://*:44000");
    if (r == -1) {
        printf(zmq_strerror(errno));
    }
}
void publishdata(int x, int y) {
    if (datasocket == 0) {
        setup_msg_publish();
    }
    zmq_data zd;
    zd.msgType = int 0;
    zd.x = x;
    zd.y = y;
    size_t len = sizeof(zd);
    int res = zmq_send(datasocket, &zd, len, NULL);
    assert(res == len);
}

I've tried to implement this in Python:

import zmq
import pickle
from collections import namedtuple
Data = namedtuple("Data", "msgType x y")
def send_zmq():
    data = Data("0", "1", "2")
    msg = pickle.dumps(data)  

    context = zmq.Context()
    socket = context.socket(zmq.REQ)
    socket.connect("tcp://127.0.0.1:44000")
    socket.send(msg)

For debug purposes I can recive the data with Python like this:

import zmq
import pickle
context = zmq.Context()

socket = context.socket(zmq.REP)
socket.bind("tcp://127.0.0.1:44000")

while True:
    message = socket.recv()
    data = pickle.loads(message)
    print(data)

But I don't receive anything in my c++ code (it just prints no data):

#include "View.h"
#include <iostream>
#include <thread>
#include <chrono>

View::View() :
    viewSubscriber(zmqcontext, ZMQ_SUB)
{
    unsigned _int16 msgType = 0;
    viewSubscriber.connect("tcp://127.0.0.1:44000");
    //viewSubscriber.setsockopt(ZMQ_SUBSCRIBE, &msgType, sizeof(msgType));
    viewSubscriber.setsockopt(ZMQ_SUBSCRIBE, "", 0);
    std::cout << msgType;
}

void View::run() {
    using namespace std;
    bool received_view_data = false;

    bool checkForMore = true;
    zmq_view data;
    while (checkForMore) {
        zmq::message_t msg;
        //cout << &msg;
        if (viewSubscriber.recv(&msg, ZMQ_NOBLOCK)) {
            received_view_data = true;
            memcpy(&data, msg.data(), sizeof(data));
            cout << &data.x;
        }
        else {
            std::this_thread::sleep_for(std::chrono::milliseconds(500));
            cout << "no data \n"; 
        }
    }
}

int main(){
    View *app = new View();
    app -> run();
    return 0;
}

Any ideas what to fix so I receive the data in the namedTuple on the c++ side? Could it be that the c++ "needs to know more" about the type of each attribute of the namedTuple (if that is the case how do I specify whether the data is a double or int etc?)?


Solution

  • The solution was found after testing to go from C++ -> Python thank you J_H for the idea. Instead of using a namedtuple a packed struct was used.

    import zmq
    import struct
    def send_zmq():
        struct_format = 'Idd'
        msg_type = 0
        x = 1.0
        y = 1.0
        msg = struct.pack(struct_format, msg_type, x, y)
        context = zmq.Context()
        socket = context.socket(zmq.REQ)
        socket.connect("tcp://127.0.0.1:44000")
        socket.send(msg)