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

时间:2017-01-23 09:50:10

标签: c++ concurrency zeromq

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

2 个答案:

答案 0 :(得分:6)

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

这就是&#34;魔法&#34; - REP套接字负责将响应发送到正确的客户端。如果客户端已断开连接,则只丢弃回复消息。

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

  

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

答案 1 :(得分:1)

glib(并不是非常有用)的答案是,它的作用是因为它们是这样写的。

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

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

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

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