Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Json object from string from a TCP socket #1504

Closed
marcociara379 opened this issue Mar 6, 2019 · 7 comments
Closed

Json object from string from a TCP socket #1504

marcociara379 opened this issue Mar 6, 2019 · 7 comments
Labels
kind: question solution: proposed fix a fix for the issue has been proposed and waits for confirmation

Comments

@marcociara379
Copy link

Hello everyone,
I am trying to pass some information from a Python script to a C++ program. The communication occurs with zmq via TCP. The Python publisher publishes the following info:

topic = "vPad_pos_body_frame"
position_orientation_dict = dict(x_NED=str(0.0),
                                    y_NED=str(1.0),
                                    z_NED=str(2.0),
                                    pose_w=str(3.0),
                                    pose_x=str(4.0),
                                    pose_y=str(5.0),
                                    pose_z=str(6.0) )
send_str_and_json(socket_manager, topic, json.dumps(position_orientation_dict))

where the function send_str_and_json() looks like:

def send_str_and_json(socket, string, json_dict, flags=0):
    """send a dictionary as json with the topic string"""
    socket.send_string(string, zmq.SNDMORE)
    return socket.send_json(json_dict, flags)

On the C++ program, I am able to receive the dumped json string, but as soon as I try to access the keys:values after parsing, an error rises: terminate called after throwing an instance of 'nlohmann::detail::type_error' what(): [json.exception.type_error.305] cannot use operator[] with a string argument with string Aborted (core dumped).
As far as I can tell, the string is not parsed to create an object, but it remains a string. (confirmed by nlohmann::json::is_object() that returns 0. The string is correctly received by the software, and i can print it ("{\"x_NED\": \"0.0\", \"y_NED\": \"1.0\", \"z_NED\": \"2.0\", \"pose_w\": \"3.0\", \"pose_x\": \"4.0\", \"pose_y\": \"5.0\", \"pose_z\": \"6.0\"}")
The code of the subscriber program in C++ is the following:

#include <iostream>
#include <string>
#include <zmq.hpp>
#include <json.hpp>
#include <unistd.h>

/* test program to listen to the track_vPad.py output (pad position in body frame) sent on port 5556 */

int main()
{
    std::string topic = "vPad_pos_body_frame";
    zmq::context_t context(1);
    zmq::socket_t subscriber(context, ZMQ_SUB);
    // subscriber.setsockopt(ZMQ_SUBSCRIBE, "vPad_pos_body_frame", 1);
    subscriber.connect("tcp://127.0.0.1:6543");
    subscriber.setsockopt(ZMQ_SUBSCRIBE, topic.c_str(), topic.length());
    std::cout << "Connected. "<< std::endl;
    nlohmann::json j;

    sleep(1);

    while(true)
    {
        zmq::message_t msg;
        subscriber.recv(&msg);
        std::string topic_str = std::string(static_cast<char*>(msg.data()), msg.size());
        std::cout << "Received topic " << topic_str << " " << std::endl;
        if( std::string(static_cast<char*>(msg.data())) == topic)
        {

            zmq::message_t json_msg;
            subscriber.recv(&json_msg);
            std::string json_str = std::string(static_cast<char*>(json_msg.data()), json_msg.size());
            // std::stringstream(json_str) >> j;
            j = nlohmann::json::parse(json_str);
            std::cout << j.is_object() << std::endl;
            std::string x_NED; 
            x_NED = j["x_NED"];
            std::cout << "Received JSON: \n" <<  x_NED << " \n \n " << std::endl;
        }
    }
    return 0;
}

Do you have any clue on how to create a json object from the string passed through TCP and then access its keys:values?

Thanks a lot for your help,

Marco

PS:

  • the json library tests during compilation report no errors.
  • I use Ubuntu 18.04
@pboettch
Copy link
Contributor

pboettch commented Mar 6, 2019

What do you get if you print out json_str? Is it what you pasted in your post - the one which espaces the quotes?

For performance reasons you should consider using cbor (with cbor2 in python) for data-sending. In my use-case I reduced the cpu-load by 15% when switching to cbor instead of json-strings.

Also, there is a json-parse (as well as for cbor) function which accepts a const uint8_t *-pointer, This saves you from copying the string to std::string.

@marcociara379
Copy link
Author

Hi @pboettch,
thanks a lot for your precious hints.
Yes, if I print json_str the output is:
"{\"x_NED\": \"0.0\", \"y_NED\": \"1.0\", \"z_NED\": \"2.0\", \"pose_w\": \"3.0\", \"pose_x\": \"4.0\", \"pose_y\": \"5.0\", \"pose_z\": \"6.0\"}".

Marco

@pboettch
Copy link
Contributor

pboettch commented Mar 6, 2019

This means that the string you are sending from python has been double-dumped as json. If you print json_dict in your send_str_and_json python function, what does it show?

@marcociara379
Copy link
Author

{"x_NED": "0.0", "y_NED": "1.0", "z_NED": "2.0", "pose_w": "3.0", "pose_x": "4.0", "pose_y": "5.0", "pose_z": "6.0"}

@marcociara379
Copy link
Author

yes, I dumped twice, apparently the zmq send_json already "dumps" it.
Thanks for your help, you have been extremely useful.
By the way, if you have a couple of minutes, would you mind explain a bit more about the json-parse function, so that I do not have to copy to a std::string the sent json?

Thanks a lot again

@pboettch
Copy link
Contributor

pboettch commented Mar 6, 2019

Just check the possible ::parse-function of nlohmann::json in the documentation. You will find one which is parse(const uint8_t *, size_t) or similar.

@marcociara379
Copy link
Author

awesome, I close the issue since you solved it.

have a nice day.

@nlohmann nlohmann added kind: question solution: proposed fix a fix for the issue has been proposed and waits for confirmation labels Mar 10, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
kind: question solution: proposed fix a fix for the issue has been proposed and waits for confirmation
Projects
None yet
Development

No branches or pull requests

3 participants