I'm trying to recreate the Router-to-Router example from PyZMQ using cppzmq. I tested the Python version and the behavior is as expected (i.e., client connects to server, server sends reply).
However, my C++ version gets stuck on the initial connect (or throws a host unreachable error if router_mandatory
is set).
Changing the client socket type to dealer leads to the expected message flow.
I suspect that I messed up the identities/routing somehow, but I'm too stuck to see where I went wrong.
server.cpp
#include <zmq.hpp>
#include <zmq_addon.hpp>
#include <iostream>
#include <vector>
#include <string>
int main() {
zmq::context_t context(1);
zmq::socket_t server(context, zmq::socket_type::router);
server.set(zmq::sockopt::routing_id, "server");
server.bind("tcp://*:4000");
while (true) {
std::cout << "Waiting for msg" << std::endl;
std::vector<zmq::message_t> recv_msgs;
zmq::recv_multipart(server, std::back_inserter(recv_msgs));
std::string received_message(static_cast<char*>(recv_msgs[1].data()), recv_msgs[1].size());
std::cout << "Received message: " << received_message << std::endl;
server.send(recv_msgs[0], zmq::send_flags::sndmore);
server.send(zmq::message_t(), zmq::send_flags::sndmore);
server.send(zmq::buffer("Response from server"), zmq::send_flags::none);
}
return 0;
}
client.cpp
#include <zmq.hpp>
#include <zmq_addon.hpp>
#include <array>
#include <iostream>
#include <string>
int main() {
zmq::context_t context(1);
zmq::socket_t client(context, zmq::socket_type::router);
client.set(zmq::sockopt::routing_id, "client");
client.connect("tcp://127.0.0.1:4000");
// Send a request to the server
std::array<zmq::const_buffer, 3> bufs = {
zmq::buffer("server"), // set identity of server we try to reach
zmq::str_buffer(""),
zmq::str_buffer("Hello, Server!")
};
zmq::send_multipart(client, bufs);
// Receive the response
zmq::message_t reply;
zmq::message_t identity;
client.recv(identity, zmq::recv_flags::none);
client.recv(reply, zmq::recv_flags::none);
std::string reply_message(static_cast<char*>(reply.data()), reply.size());
std::cout << "Received reply: " << reply_message << std::endl;
return 0;
}
Modify your client.cpp
according to the following patch:
--- client1.cc 2024-08-18 21:07:00.000000000 +0000
+++ client2.cc 2024-08-18 21:08:00.000000000 +0000
@@ -1,18 +1,21 @@
#include <zmq.hpp>
#include <zmq_addon.hpp>
#include <array>
+#include <chrono>
#include <iostream>
#include <string>
+#include <thread>
int main() {
zmq::context_t context(1);
zmq::socket_t client(context, zmq::socket_type::router);
client.set(zmq::sockopt::routing_id, "client");
client.connect("tcp://127.0.0.1:4000");
+ std::this_thread::sleep_for(std::chrono::milliseconds{100});
// Send a request to the server
std::array<zmq::const_buffer, 3> bufs = {
- zmq::buffer("server"), // set identity of server we try to reach
+ zmq::str_buffer("server"), // set identity of server we try to reach
zmq::str_buffer(""),
zmq::str_buffer("Hello, Server!")
};
There are two changes:
client.connect(...)
returns. A small delay ensures the connection is established and the message gets delivered.str_buffer
.Regarding the connection:
Relaying on a delay is racy and not ideal. A better solution would probably be to monitor the connection state via zmq_socket_monitor (or it's cppzmq equivalent) and wait for ZMQ_EVENT_CONNECTED
. I would hope this event gets delivered after the connection is fully established (the routing IDs exchanged), but I'm not sure. Worth a try.