Reputation: 113
From the documentation at: https://brettviren.github.io/cppzmq-tour/index.html#intro, it seems that it is possible with CPPZMQ to send and receive a standard vector by using messages or buffers. However, I have not been able to use the vector from the subscriber, I get an error when trying to access it:
Segmentation error (core dumped)
when I run the following code:
Publisher:
#include <vector>
#include <iostream>
#include <zmq.hpp>
#include <thread>
using namespace std;
using namespace zmq;
int main()
{
vector<float> v(2, 0.0);
context_t ctx;
socket_t pub(ctx, ZMQ_PUB);
const std::string addr = "tcp://127.0.0.1:5678";
pub.bind(addr);
while (true)
{
std::this_thread::sleep_for(std::chrono::milliseconds(100));
v = {0.1, 0.2};
message_t msg(v);
auto res = pub.send(msg, send_flags::none);
cout << "message sent" << endl;
}
}
Subscriber:
#include <vector>
#include <iostream>
#include <zmq.hpp>
using namespace std;
using namespace zmq;
int main()
{
context_t ctx;
socket_t sub(ctx, socket_type::sub);
const std::string addr = "tcp://127.0.0.1:5678";
sub.set(zmq::sockopt::subscribe, "");
sub.connect(addr);
message_t msg;
const vector<float>* iptr = msg.data<vector<float>>();
while (true)
{
if (sub.recv(msg, zmq::recv_flags::none))
{
cout << "msg received" << endl;
iptr = msg.data<vector<float>>();
cout << "iptr: " << iptr << endl;
cout << "element 0: " << (*iptr)[0] << "endl";
}
}
}
My question is:
How do I retrieve the vector in the publisher ? More generally, with a vector of constant length and type, I would need an efficient way to send and receive such vector, for example avoiding copy and avoiding reallocation and destruction at every message. What is the recommended way to do that ?
Upvotes: 0
Views: 1028
Reputation: 8228
Constructing zmq::message_t
directly from STL vector is ok, because iterator based constructor will be called.
std::vector<float> v({0.1, 0.2});
message_t msg(v);
It will internally copy the content of the vector to the underlying zmq_msg_data
casted to float*
:
std::copy(first, last, data<value_t>()); // value_t == float in this case
However, templated version of message_t::data
method
template<typename T> T *data() ZMQ_NOTHROW { return static_cast<T *>(data()); }
is just a static cast from void*
to your T*
. So if you invoke it like that: msg.data<vector<float>>();
you try to cast raw buffer to complex std::vector
class, which is incorrect. Instead, you can copy received raw data to newly created float vector:
std::vector<float> vec;
vec.resize(msg.size()/sizeof(float)); // note that msg size must be divisible by float size
std::memcpy(vec.data(), msg.data(), msg.size());
Alternatively you can get already casted data float* rawData = msg.data<float>();
and use
std::copy(rawData, rawData+msg.size()/sizeof(float), std::back_inserter(vec));
Upvotes: 1