ZeroMQ REQ/REP 如何处理多个客户端?

Posted

技术标签:

【中文标题】ZeroMQ REQ/REP 如何处理多个客户端?【英文标题】:How does ZeroMQ REQ/REP handle multiple clients? 【发布时间】:2017-01-23 09:50:10 【问题描述】:

我开始将 ZeroMQ 用于 IPC,并制作了一个简单的 echo-client/server,我对一件事感到惊讶。这是 C++ 代码(使用 zmq.hppzmq_addon.hpp)。

服务器:

zmq::context_t context(1);
zmq::socket_t socket(context, ZMQ_REP);
socket.bind("ipc:///tmp/machine-1");
while (1) 
    zmq::multipart_t m;
    m.recv(socket);
    int i = m.poptyp<int>();
    i++;
    m.addtyp<int>(i);
    m.send(socket);

客户:

zmq::context_t context(1);
zmq::socket_t socket(context, ZMQ_REQ);

socket.connect("ipc:///tmp/machine-1");

int i = 0;
while (1) 
    int save = i;
    zmq::multipart_t m;
    m.addtyp<int>(i);
    m.send(socket);
    m.recv(socket);

    i = m.poptyp<int>();

    if (i != (save + 1))
        break;

    if ((i % 100000) == 0)
        std::cerr << "i : " << i<< "\n";

我按预期工作。客户端发送int,服务器加一并将其发回。

现在我不明白的魔力:我意识到,我可以并行运行客户端多次,并且它继续为每个客户端正确工作。

比较 save+1i 的检查总是可以的。

ZMQ如何处理服务器端的并发问题?它如何知道必须将响应发送回哪个客户端?

关于 SO 有这个问题,但它没有回答我的问题:ZeroMQ REQ/REP on ipc:// and concurrency

【问题讨论】:

【参考方案1】:

根据 zeromq 文档,当您在服务器中调用 REP.recv() 时,它将从排队的 REQ(客户端)套接字返回一条消息。如果有多个客户端连接,它将使用公平队列策略来选择一个。当调用 REP.send() 进行回复时,REP 套接字总是将响应发送给相应的 REQ 客户端。

这就是“魔法”——REP 套接字负责将响应发送到正确的客户端。如果客户端已断开连接,它只会丢弃回复消息。

docs 可能比我的解释更清楚:

ZMQ_REP:服务使用 ZMQ_REP 类型的套接字来接收 来自客户端的请求和向客户端发送回复。这种插座类型允许 只有 zmq_recv(request) 和后续的交替序列 zmq_send(reply) 调用。收到的每个请求都是公平排队的 所有客户端,并且发送的每个回复都被路由到发出的客户端 最后一个请求。如果原始请求者不再存在 回复被静默丢弃。

【讨论】:

我只阅读了指南,您在zmq_connect 的文档中是对的,它的描述很好。关键是,ZMQ_REQ/ZMQ_RES 连接也需要一定的接收/发送模式。因此,他们可以在调用 recv 时锁定对套接字的访问,并在调用 send 时释放它(反之亦然)【参考方案2】:

油嘴滑舌(但不是很有用)的答案是,它之所以有效,是因为他们是这样写的。

更长的答案:ZMQ 团队所做的是在流连接(ipc 管道、套接字等)之上实现他们自己的消息传递协议 (zmtp)。除了传递和划分消息外,他们还在此协议中添加了专门用于支持不同模式的功能,例如 REQ/REP、PUB/SUB、公平排队等。为了使其工作,运行了一个 zmq 库线程来处理所有zmtp活动在后台,你通过调用zmq_send、zmq_poll等与这个线程交互。使用zmtp意味着套接字另一端的程序也必须在说zmtp;如果一端使用 libzmq 而另一端只是为自己打开原始套接字,则不会发生任何有用的事情。

这确实是一段非常有用的代码。

在我看来,这绝对是要走的路。 ZMQ 成功地将两个执行线程之间的连接概念抽象为不再关心它们是否在同一台机器上、在同一进程中、由网络连接分隔等等。这使得应用程序开发变得容易 - 任何事情可以去任何地方(忽略与网络速度和延迟相关的问题)。

我猜你甚至可以将一个 zmq 套接字绑定到两个不同的传输,例如 ipc 和 tcp。太实用了!

【讨论】:

以上是关于ZeroMQ REQ/REP 如何处理多个客户端?的主要内容,如果未能解决你的问题,请参考以下文章

Thrift 如何处理被拆分为多个消息的 Zlib 刷新标记?

WebSocket 服务器如何处理多个传入的连接请求?

Aerospike如何处理通过多个连接创建同一记录?

如何处理淘汰视图模型中的多对多关系

我们如何处理具有单个实体类的多个存储过程

Nginx如何处理一个连接