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

How does ZeroMQ REQ/REP handle multiple clients?

我开始使用 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

根据 zeromq 文档,当您在服务器中调用 REP.recv() 时,它将 return 来自排队的 REQ(客户端)套接字的消息。如果连接了多个客户端,它将使用 fair-queue 策略来选择一个。当您调用 REP.send() 进行回复时,REP 套接字始终将响应发送到相应的 REQ 客户端。

那就是 "magic" - REP 套接字负责将响应发送到正确的客户端。如果客户端已断开连接,它只会丢弃回复消息。

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

ZMQ_REP: A socket of type ZMQ_REP is used by a service to receive requests from and send replies to a client. This socket type allows only an alternating sequence of zmq_recv(request) and subsequent zmq_send(reply) calls. Each request received is fair-queued from among all clients, and each reply sent is routed to the client that issued the last request. If the original requester does not exist any more the reply is silently discarded.

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

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

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

在我看来,这绝对是正确的选择。 ZMQ 成功地抽象了两个执行线程之间的连接的想法,以至于人们不再关心它们是否在同一台机器上,在同一进程中,是否被网络连接分开等。这使得应用程序开发变得容易 - 任何东西可以去任何地方(忽略与网络速度和延迟相关的问题)。

我了解到您甚至可以将 zmq 套接字绑定到两种不同的传输方式,例如 ipc 和 tcp。太有用了!