ZMQ Hello world does not work - c++

I try to run simple ZMQ application ( ROUTER/DEALER ).
I just send a request from DEALER to ROUTER, send it back. But DEALER cannot receive it.
I run it in one process ( ROUTER has its own thread ).
#include <zmq.hpp>
#include <string>
#include <iostream>
#include <thread>
void router()
{
zmq::context_t context(1);
zmq::socket_t socket(context, ZMQ_ROUTER);
socket.bind("tcp://*:5561");
while(1)
{
// Wait for next request from client
zmq::message_t reply;
socket.recv (&reply);
std::cout << "Router: Received request" << std::endl;
// Send reply back to client
std::string string= "example";
zmq::message_t message(string.size());
memcpy (message.data(), string.data(), string.size());
std::cout << "Router: Sending" << std::endl;
socket.send (message);
}
}
int main ()
{
std::thread t{&router};
// Prepare our context and socket
zmq::context_t context (2);
zmq::socket_t socket (context, ZMQ_DEALER);
std::cout << "Dealer: Connecting to hello world server…" << std::endl;
socket.connect ("tcp://127.0.0.1:5561");
for (int i = 0; i != 10; i++)
{
zmq::message_t request (5);
memcpy (request.data (), "Hello", 5);
std::cout << "Dealer: Sending Hello " << i << "…" << std::endl;
socket.send (request);
zmq::message_t reply;
socket.recv (&reply);
std::cout << "Dealer: Received " << i << std::endl;
}
return 0;
}
I have an output:
Dealer: Connecting to hello world server…
Dealer: Sending Hello 0…
Router: Received request
Router: Sending
Router: Received request
Router: Sending

From ZMQ's documentation on socket :
When receiving messages a ZMQ_ROUTER socket shall prepend a message
part containing the identity of the originating peer to the message
before passing it to the application. Messages received are
fair-queued from among all connected peers. When sending messages a
ZMQ_ROUTER socket shall remove the first part of the message and use
it to determine the identity of the peer the message shall be routed
to.
So modify your code to something like this :
#include <zmq.hpp>
#include <string>
#include <iostream>
#include <thread>
#include <unistd.h>
void router()
{
zmq::context_t context(1);
zmq::socket_t socket(context, ZMQ_ROUTER);
socket.bind("tcp://*:5561");
while(1) // Fix that infinite loop or your thread won't join
{
// Wait for next request from client
zmq::message_t id;
socket.recv (&id);
zmq::message_t reply;
socket.recv (&reply);
std::cout << std::string(static_cast<char*>(reply.data()),reply.size()) << std::endl;
std::cout << "Router: Received request" << std::endl;
// Send reply back to client
zmq::message_t copy_id;
copy_id.copy(&id);
std::string string= "example";
zmq::message_t message(string.size());
memcpy (message.data(), string.data(), string.size());
std::cout << "Router: Sending" << std::endl;
socket.send(id, ZMQ_SNDMORE);
socket.send(message);
}
sleep(1);
socket.setsockopt(ZMQ_LINGER, 0);
socket.close();
context.close();
}
int main ()
{
std::thread t{&router};
// Prepare our context and socket
zmq::context_t context (2);
zmq::socket_t socket (context, ZMQ_DEALER);
std::cout << "Dealer: Connecting to hello world server…" << std::endl;
socket.connect ("tcp://127.0.0.1:5561");
for (int i = 0; i != 10; i++)
{
zmq::message_t request (5);
memcpy (request.data (), "Hello", 5);
std::cout << "Dealer: Sending Hello " << i << "…" << std::endl;
socket.send(request);
zmq::message_t reply;
socket.recv(&reply);
std::cout << "Dealer: Received " << i << std::endl;
}
socket.setsockopt(ZMQ_LINGER, 0);
socket.close();
context.close();
t.join();
return 0;
}

Related

Zeromq C++ Subscriber not receiving message

Publisher code
int main()
{
zmq::context_t ctx(0);
zmq::socket_t publisher(ctx, zmq::socket_type::pub);
publisher.bind("inproc://#1");
// Give the subscribers a chance to connect, so they don't lose any messages
std::this_thread::sleep_for(std::chrono::seconds(5));
std::cout << "Publisher Started Publishing messages";
while (true)
{
// Write three messages, each with an envelope and content
publisher.send(zmq::str_buffer("A"), zmq::send_flags::sndmore);
publisher.send(zmq::str_buffer("Message in A envelope"));
publisher.send(zmq::str_buffer("B"), zmq::send_flags::sndmore);
publisher.send(zmq::str_buffer("Message in B envelope"));
publisher.send(zmq::str_buffer("C"), zmq::send_flags::sndmore);
publisher.send(zmq::str_buffer("Message in C envelope"));
std::this_thread::sleep_for(std::chrono::seconds(10));
}
}
Subscriber code
int main() {
zmq::context_t ctx(0);
zmq::socket_t subscriber(ctx, zmq::socket_type::sub);
subscriber.connect("inproc://#1");
// Thread3 opens ALL envelopes
subscriber.set(zmq::sockopt::subscribe, "A");
std::this_thread::sleep_for(std::chrono::milliseconds(2000));
while (1) {
// Receive all parts of the message
std::vector<zmq::message_t> recv_msgs; std::cout << "Connected to Publisher";
zmq::recv_result_t result =
zmq::recv_multipart(subscriber, std::back_inserter(recv_msgs));
assert(result && "recv failed");
assert(*result == 2);
std::cout << "Thread3: [" << recv_msgs[0].to_string() << "] "
<< recv_msgs[1].to_string() << std::endl;
}
}
I trying to apply zeromq pub-sub pattern created both publisher and subscriber in c++. The message published by publisher is not getting received by the subscriber.

zmq::message_t assign a string

I am trying to familiarize myself with ZeroMQ by creating a simple socket communication betwenn a publisher and a subscriber to send a test message. However, I can't find the information I want on how to put a string inside a zmq::message_t type message. Indications pointed to the use of "std::memcpy(message.data(), ms.data(), ms.size())" which I tried. However, by debuging the coding using Watchs, I see that the message is still empty after execution:
WATCH IMAGE and it is also empty when I print it out using a cout: Cmd
Is there another way to assign a string to a zmq::message_t message or is there something else wrong here?
My entire code is:
int main()
{
zmq::context_t context(1);
zmq::socket_t pub(context, ZMQ_PUB);
pub.bind("tcp://*:5555");
std::cout << "Pub Connected" << std::endl;
zmq::socket_t sub(context, ZMQ_SUB);
sub.connect("tcp://localhost:5555");
std::cout << "Sub Connected" << std::endl;
std::stringstream s;
s << "Hello World";
auto ms = s.str();
zmq::message_t message(ms.size());
memcpy(message.data(), ms.c_str(), ms.length());
pub.send(message, zmq::send_flags::none);
std::cout << "message: " << message << std::endl;
zmq_sleep(1);
sub.set(zmq::sockopt::subscribe, "Hello World");
zmq::message_t rx_msg;
sub.recv(rx_msg,zmq::recv_flags::none);
std::string rx_str;
rx_str.assign(static_cast<char*>(rx_msg.data()), rx_msg.size());
std::cout << "Message: " << rx_str << "received!" << std::endl;
}
There is a constructor for zmq::message_t that has the signature (docs)
message_t(const void *data_, size_t size)
so you could use this like
zmq::message_t message(static_cast<void*>(ms.data()), ms.size());

How to Send messages between server and client using C++ standard library networking TS

I have tried following the tutorial from boost, however the API is not identical so I have had to guess some parts.
My attempt so far is shown bellow:
#include <iostream>
#include <experimental/internet>
#include <experimental/socket>
#include <thread>
#include <chrono>
using namespace std::experimental;
int main(int argc, char* argv[])
{
std::thread server = std::thread([]()
{
std::cout << "Starting server" << std::endl;
net::io_context context;
net::ip::tcp::endpoint endpoint{net::ip::tcp::v4(), 1234};
net::ip::tcp::acceptor acceptor{context, endpoint};
acceptor.non_blocking(true);
std::cout << "opened server on " << endpoint << std::endl;
std::error_code error;
net::ip::tcp::socket socket(context);
while (true)
{
socket = acceptor.accept(error); //accept connections
if (!error) //if connected with a client
{
std::cout << "Connected to client!" << std::endl;
std::this_thread::sleep_for(std::chrono::seconds(2));
std::string data = "Hello World!";
net::const_buffer buf(&data, sizeof(data));
socket.send(buf);
std::cout << "Sent data!" << std::endl;
while(true) {}
}
}
});
std::thread client = std::thread([]()
{
net::io_context context;
net::ip::tcp::socket socket(context);
net::ip::tcp::endpoint server{net::ip::tcp::v4(), 1234};
std::error_code error;
while(true)
{
socket.connect(server, error); //attempt to connect
if (!error) //if connected
{
std::cout << "Connected to server!" << std::endl;
net::mutable_buffer buf;
while(buf.size() == 0)
{
socket.receive(buf);
}
std::cout << "Received data!" << std::endl;
std::cout << buf.data() << std::endl;
while(true) {}
}
}
});
server.join();
return 0;
}
The sever and client connect, but the message is not received by the client. The output from the program above is:
Starting server
opened server on 0.0.0.0:1234
Connected to server!
Connected to client!
Sent data!
And then it waits forever.
How do I get the socket to correctly receive the data?
This
std::string data = "Hello World!";
net::const_buffer buf(&data, sizeof(data));
is wrong. You want to send content of data string, not its internal bytes. &data gives you a pointer to underlying data of string instance, not its content. If you want to create buffer which represents content of data you can do:
const std::string data = "Hello World!";
net::const_buffer buf = net::buffer(data);
This
net::mutable_buffer buf;
while(buf.size() == 0)
{
socket.receive(buf);
}
gives you infinite loop because initial size of buf is 0, so receive reads 0 bytes and returns. Then while condition is checked, buf's size is still 0, and the loop goes on.
Before calling receive you need to specify the size of buffer - it indicates how many bytes must be read. You are sending Hello World! so
std::string msg;
msg.resize(12); // prepare space for incoming data
net::mutable_buffer buf = net::buffer(msg);
socket.receive(buf);
std::cout << "I got: " << msg << std::endl;

Receiving 0 size messages while using ZMQ and protobuf

I am trying to set up a basic communication system between client and server using ZMQ. I am using protobuf for the message format.
My problem is when I send the message from client the message size is 34 but the message size received on the server is 0.
Following is my code;
Client.cpp
tutorial::Person person;
person.set_id(1234);
person.set_name("john");
person.set_email("john#mxyz.com");
person.set_phonenumber("12345678");
zmq::context_t context (1); // Prepare our context and socket
zmq::socket_t socket (context, ZMQ_PAIR);
std::cout << "Connecting to server…" << std::endl;
int linger = 0;// ms
socket.setsockopt(ZMQ_LINGER, &linger, sizeof(linger));
socket.connect ("tcp://127.0.0.1:20000");
std::string msg_str;
person.SerializeToString(&msg_str);
std::cout << "Size of message string is "<< msg_str.size()<<std::endl;
zmq::message_t request (msg_str.size());
memcpy ((void *) request.data (), msg_str.c_str(), msg_str.size());
std::cout << "Sending Person data ..." << std::endl;
socket.send (request);
socket.close();
google::protobuf::ShutdownProtobufLibrary();
return 0;
Server.cpp :
zmq::context_t context(1); // Prepare our context and socket
zmq::socket_t socket(context, ZMQ_PAIR);
int linger = 0; // ms
socket.setsockopt(ZMQ_LINGER, &linger, sizeof(linger));
socket.bind("tcp://127.0.0.1:20000");
while (true)
{
zmq::message_t request;
int recieved = socket.recv(&request);
std::string msg(static_cast<char*>(request.data()),request.size());
std::cout<<"Size of message recieved is "<< msg.size()<<std::endl;
tutorial::Person person;
person.ParseFromString(msg);
std::string text_str1;
google::protobuf::TextFormat::PrintToString(person, &text_str1);
}
socket.close();
Output of Client is :
Size of message string is 34
Output of server is :
Size of message received is 0
I have tried tried switching to ParseToArray also but it did not help.
Any kind of help is appreciated.
I have solved it with another way. Actually earlier I installed libzmq lib , but later when I switched to libzmq3-dev it worked for me.
I had the exact same problem; what I found is that the zmq::message_t had to go out of scope OR rebuild needed to be called.
For example, if the publisher looked like this.
zmq::message_t msg(3);
memcpy(msg.data(), "abc", 3);
while (1 == 1) {
pubSocket.send(msg);
sleep(1);
}
The subscriber would receive messages of zero length. If the code was changed to
while (1 == 1) {
zmq::message_t msg(3);
memcpy(msg.data(), "abc", 3);
pubSocket.send(msg);
sleep(1);
}
OR
zmq::message_t msg(3);
memcpy(msg.data(), "abc", 3);
while (1 == 1) {
pubSocket.send(msg);
msg.rebuild(3);
sleep(1);
}
Then the subscriber would receive a 3-byte message.

Zeromq: How to access tcp message in c++

I am a new-by to ZeroMQ and make my way through the C++ hello-world example of the echo client-server pattern (Request-Reply). The server looks like:
//
// Hello World server in C++
// Binds REP socket to tcp://*:5555
// Expects "Hello" from client, replies with "World"
//
#include <zmq.hpp>
#include <string>
#include <iostream>
#include <unistd.h>
int main () {
// Prepare our context and socket
zmq::context_t context (1);
zmq::socket_t socket (context, ZMQ_REP);
socket.bind ("tcp://*:5555");
while (true) {
zmq::message_t request;
// Wait for next request from client
socket.recv (&request);
std::cout << "Received Hello" << std::endl;
// Do some 'work'
sleep (1);
// Send reply back to client
zmq::message_t reply (5);
memcpy ((void *) reply.data (), "World", 5);
socket.send (reply);
}
return 0;
}
Now my question: How can I access / read the real data that socket.recv() ? Trying:
std::cout << request << std::endl;
resulted in an error message:
error: no match for ‘operator<<’ in ‘std::operator<< [with _Traits =
std::char_traits<char>](((std::basic_ostream<char, std::char_traits<char> >&)
(& std::cout)), ((const char*)"Received Hello")) << request’
The same goes for the client side that is sending the message. I don't find a way to display the real message...
The hello world example goes only half way and outputs the hard-coded values:
std::cout << "Received Hello" << std::endl;
Printing the actual response can be done as follows:
zmq::message_t reply;
socket.recv (&reply);
std::string rpl = std::string(static_cast<char*>(reply.data()), reply.size());
std::cout << rpl << std::endl;
There are some other useful examples in zhelpers.hpp.
I found that the following does what I want:
zmq::message_t request (msglen);
memcpy ( (void *) request.data(), myMessage, msglen);
char * requestmsg = new char [msglen];
memcpy (requestmsg, request.data(), request.size());
requestsocket.send (request);
std::cout << "Sending " << requestmsg << std::endl;
where msglen is of type int and myMessage is const char * tyoe.
In this way, the server receives a human readable message.
Hope this is not against any zeromq rules...
While I think we need to go through the guide before we can write elegant ZeroMQ codes. I found lines of simple codes from the HELLO WORLD example for extracting data received from the socket and sending back response:
zmq::message_t request;
socket.recv (&request);
std::cout << "Received request: [" << (char*) request.data() << "]" << std::endl;
// Do some 'work'
Sleep (1);
// Send reply back to client
zmq::message_t reply (6);
memcpy ((void *) reply.data (), "World", 6);
socket.send (reply);
However, this solution does not specify the length of received data, following Nikolai Koudelia's way above, I make a string for received data:
std::cout << "Received request: [" << std::string(static_cast<char*>(request.data()), request.size()) << "]" << std::endl;