Router绑定inproc地址时,如何向ZeroMQ Workers发送请求?
问题
现有基于ZeroMQ的程序架构如下:
- Clients (REQ) → Router → Proxy → Dealer → Workers (REP)
- Router绑定到
inproc://router地址 - Dealer绑定到TCP地址
0.0.0.0:5555 - Workers部署在远程
需要在自己的程序中向Workers发送请求并接收回复,但无法连接到绑定inproc地址的Router,且无法修改现有程序,是否有可行方案?
现有程序的C++实现代码:
#include <chrono> #include <functional> #include <thread> #include <vector> #include <spdlog/spdlog.h> #include <zmq.hpp> void Proxy(zmq::context_t& context) { zmq::socket_t clients { context, zmq::socket_type::router }; zmq::socket_t workers { context, zmq::socket_type::dealer }; clients.bind("inproc://router"); workers.bind("tcp://0.0.0.0:5555"); zmq::proxy(clients, workers); } void Client(zmq::context_t& context) { using namespace std::chrono_literals; zmq::socket_t socket { context, zmq::socket_type::req }; socket.connect("inproc://router"); for (;;) { socket.send(zmq::str_buffer("some request")); zmq::message_t reply; socket.recv(reply); spdlog::trace("reply: {}", reply.to_string()); std::this_thread::sleep_for(1s); } } void Worker(zmq::context_t& context) // actually located remotely { zmq::socket_t socket { context, zmq::socket_type::rep }; socket.connect("tcp://localhost:5555"); for (;;) { zmq::message_t request; socket.recv(request); spdlog::trace("request: {}", request.to_string()); socket.send(zmq::str_buffer("some reply")); } } int main() { zmq::context_t context { 1 }; std::jthread proxy { Proxy, std::ref(context) }; std::vector<std::jthread> workers; for (int i = 0; i < 4; ++i) { workers.emplace_back(Worker, std::ref(context)); } std::vector<std::jthread> clients; for (int i = 0; i < 4; ++i) { clients.emplace_back(Client, std::ref(context)); } return 0; }
已尝试的方法:自行搭建Router-Proxy-Dealer结构,将Dealer连接到现有Dealer的0.0.0.0:5555地址,向自身Router发送请求。Wireshark确认请求已发送到现有Dealer,但Dealer未转发给Workers,未成功。
求无需从零实现套接字通信的解决方法。
解决方案
现有程序的Proxy逻辑是:Router接收同进程内REQ客户端的单帧请求,自动添加客户端身份帧后转发给Dealer,Dealer再将多帧消息转发给已连接的REP Worker;Worker回复单帧消息,经Dealer、Router原路返回给客户端。
直接连接Dealer失败的原因是:普通REQ套接字发送的单帧消息不符合Dealer期望的多帧格式(身份帧+数据帧),因此不会被转发给Worker。无需修改现有程序的可行方案如下:
核心思路:用DEALER套接字模拟Router的请求格式
创建DEALER类型套接字连接到现有Dealer,按照身份帧+数据帧的格式发送请求,即可被Proxy正常转发到Worker,并接收回复。
示例代码(C++)
#include <zmq.hpp> #include <spdlog/spdlog.h> #include <string> int main() { zmq::context_t context{1}; // 使用DEALER套接字,支持多帧消息发送 zmq::socket_t custom_client{context, zmq::socket_type::dealer}; // 替换为现有程序所在主机的IP地址 std::string dealer_addr = "tcp://127.0.0.1:5555"; custom_client.connect(dealer_addr); // 发送请求:先发送空身份帧(Router会自动为REQ客户端生成身份帧,这里用空帧模拟即可) custom_client.send(zmq::message_t(), zmq::send_flags::sndmore); // 发送实际请求数据 custom_client.send(zmq::str_buffer("your custom request content")); // 接收Worker的回复 zmq::message_t reply; custom_client.recv(reply); spdlog::info("Received worker reply: {}", std::string(static_cast<char*>(reply.data()), reply.size())); return 0; }
原理说明
- DEALER套接字支持多帧消息发送,符合Proxy中Router转发给Dealer的消息格式(身份帧+数据帧)
- 现有Dealer收到该多帧消息后,会自动转发给已连接的REP Worker,Worker仅会接收并处理最后一帧的请求数据
- Worker回复的单帧消息会经Dealer原路返回给你的DEALER套接字,直接接收即可
此方案无需修改现有程序,也无需从零实现完整的套接字代理逻辑,仅需模拟Router的请求格式即可完成通信。
内容的提问来源于stack exchange,提问作者user21152820
相关产品推荐
相关产品推荐

