1

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?)?

axel_ande
  • 359
  • 1
  • 4
  • 20
  • 1
    Look at the syntax highlighting above, it highlights that your code is not valid Python, so asking about it is meaningless. That said, asking for "ideas what to improve" is asking for opinions, which is usually considered off-topic here. For code reviews, there is a separate site, make sure to read their guidelines first though! – Ulrich Eckhardt Apr 22 '22 at 09:06
  • Hi I now updated the code (missing import and a missing `"` ) and clarified my question – axel_ande Apr 22 '22 at 09:17
  • 1
    You have C++ --> C++ and python --> C++ working. Try C++ --> python. It's not clear that C++ will serialize/deserialize the same as `pickle` will. – J_H Apr 24 '22 at 20:01
  • The ZMQ_NOBLOCK, with no sleep, is weird. Wouldn't you rather block until message arrives? – J_H Apr 24 '22 at 20:02
  • I did not know there was a code review site. @UlrichEckhardt could you please elaborate? – netskink Apr 29 '22 at 14:33

1 Answers1

3

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)
axel_ande
  • 359
  • 1
  • 4
  • 20