Question

I setup a REP/DEALER connection in ZMQ and found that when REP sends one msg to DEALER, the latter must recv twice to get the message. Why is this?

The code to replicate this is a modified version of the code from this SO answer. Their code only receives once per worker, but I tested this and I only get one "world" back. I had to receive four times to get 2 "world"s back, as such:

import zmq
import time
import sys
import threading

SOCKET_NAME = "tcp://127.0.0.1:8000"
#SOCKET_NAME = "inproc://mysocket"

def dealerRoutine(context):
    socket = context.socket(zmq.DEALER)
    socket.bind(SOCKET_NAME)
    time.sleep(1)
    socket.send("", zmq.SNDMORE)
    socket.send("hello")
    socket.send("", zmq.SNDMORE)
    socket.send("hello")
    print "first msg", socket.recv()
    print "second msg", socket.recv()
    print "third msg", socket.recv()
    print "fourth msg", socket.recv()
    socket.close()


def workerRoutine(context):
    socket = context.socket(zmq.REP)
    socket.connect(SOCKET_NAME)
    s = socket.recv()
    print "worker received", s
    socket.send("world")

context = zmq.Context()

workers = []
for i in range(0, 2):
    worker = threading.Thread(target=workerRoutine, args=([context]))
    workers.append(worker) 
    worker.start()

dealerRoutine(context)

for worker in workers:
    worker.terminated = True

context.term()
Was it helpful?

Solution

I RTFM and the answer is that: ZMQ msgs to and from REP sockets are contained in envelopes. So, under the hood, a REP expects a message with a delimiter and then the message content; then, it strips away the delimiter and returns only the content to the application. This is why the DEALER sends messages like this:

socket.send("", zmq.SNDMORE)
socket.send("hello")

, because REP expects that delimiter there that it will strip off and DEALER won't do it for us automatically.

Now, when REP sends a message back to the DEALER, the inverse is true. In the application, it looks like we're just sending the data without anything extra:

socket.send("world")

However, REP sockets add a delimiter in front so that the message is sent "in an envelope" just like it was received.

So, why does DEALER need to receive twice?

Because, unlike REP, DEALER will not handle delimiters implicitly. It keeps everything as-is. Therefore, since we know it is receiving from a REP socket, we can safely receive twice, one to remove the delimiter ourself, and another to actually get the data:

socket.recv() # discard delimiter
our_data = socket.recv()

sources:

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top