How does ZeroMQ REQ/REP handle multiple clients?

Patrick B. picture Patrick B. · Jan 23, 2017 · Viewed 8.4k times · Source

I started to use ZeroMQ for IPC and made a simple echo-client/server and I'm surprised about one thing. Here is the C++ code (using zmq.hpp and zmq_addon.hpp).

Server:

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);
}

Client:

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";
}

I works as expected. The client is sending an int, the server does plus one and sends it back.

Now the magic I don't understand: I realized, that I can run the client several times in parallel and it continues to works, for each client correctly.

The check comparing save+1 to i is always OK.

How does ZMQ handles the concurrency problem on the server side? How does it know to which client the response has to be send back?

There is this question on SO, but it doesn't answer my question: ZeroMQ REQ/REP on ipc:// and concurrency

Answer

colini picture colini · Jan 23, 2017

Per the zeromq docs, when you call REP.recv() in the server it will return a message from an enqueued REQ (client) socket. If there are multiple clients connected it will use a fair-queue policy to choose one. When you call REP.send() to reply, the REP socket always sends the response to the corresponding REQ client.

That is the "magic" - the REP socket takes care of sending the response to the correct client. If the client has disconnected it just drops the reply message.

The docs may be clearer than my explanation:

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.