The current (and likely for a while) beta version of ZeroMQ, 3, is making some changes that may cause some confusion, particularly around XREP, ROUTER, XREQ and DEALER socket types. I thought I'd briefly breakdown what these types are in the two versions, as much to get it clear in my own head as anything else.

Note: if you're new to ZeroMQ, the best introduction is the ZeroMQ guide - the following wont necessarily make sense to anyone, but almost certainly will just cause more confusion if you're looking at ZeroMQ for the first time.

Firstly, it's important to remember all of these are related to the basic REP and REQ types, which stay pretty much the same in 3 (bar the addition of an ability to discard duplicate replies for REQ sockets). These simple socket types work in lockstep. REQ must first send(), then can recv(). It will send messages to connected sockets in a (mostly) round-robin manner - so if you are connected to two sockets doing send() - recv(), send() -recv(), you will send and receive first from the first socket, then the second.

Similarly, REP, must recv() then send(), and it will fair queue between all it's connected peers - if two clients send messages to to a REP socket, doing recv() - send(), recv() - send() will get one, then the other*.

XREP was the 'extended' reply device, and XREQ the 'extended' REQ device. In version 2 these remove the necessity for the lock step send/recv, but with that comes some complications to ensure that the right messages get to the right places.

XREQ is the simplest case - it simply load balances the messages it sends, and receives in fair queuing manner. As it gives the ability to send out messages in a round-robin manner, and receive replies as and when they become available, in ZeroMQ 2 the XREQ was given the friendlier name 'DEALER'. This is maintained in ZeroMQ 3, but now XREQ and DEALER are actually different types of sockets - they do exactly the same thing (for the time being), but are separate in the code, so they can be changed in the future to suit different needs. This is to reinforce a pattern that occurred naturally in the ZeroMQ development: that the X* socket types are lower level patterns, on which the 'end-user' patterns are built.

Things get a bit trickier with XREP. XREP breaks the recv() -> send() lockstep of REP, but that causes a problem - how do you send the reply back to the client that sent you the request, if many are connected? To allow this to work, XREP in ZeroMQ2 adds a message part to the front of a message, like an envelope, that includes the identity of the connection that it recv()'d the request from. That means a blank message part needed to be transparently added and removed from the stack so that REQ and REP could just return the message parts to userland code and skip these addressing elements.

So, when XREP send()s a message a reply, it reads the first message part and sends the message to the appropriate peer. Again, to give it a friendlier name ROUTER was chosen, and is an alias of XREP in 2. However, because you could explicitly set the socket identity, people started to use ROUTER/XREP as something more like a network router - by using chosen identities and sending messages to that identity without first having received a message from it. This turned out to be a bit of an anti-pattern - it made quite fragile architectures, as if a peer with the identity wasn't connected, XREP would simply drop the message. It also required some unpleasantness in the zeromq core code as the first message part became 'special', defining the peer to send the message to - there could be a stack of these as a message was passed through several ROUTERs.

Therefore, in ZeroMQ3, ROUTER and XREP have actually been split into separate types. ROUTER works the way XREP did in ZeroMQ2, adding and removing a message part. It's still a bad idea to use the router to send messages direct to nodes, but any ZeroMQ2 code that uses a 'ROUTER' socket type (for example in a simple queue device) will work properly on ZeroMQ3.

XREP however has been modified to disallow the use of manual identities, and instead of sending the message as a regular message part, it is sent as a new LABEL part. This is to indicate that the data is to be used by ZeroMQ internally, and not for general consumption, and is hidden by most socket types. The label part can be read by doing a normal recv() on an XREP, and checking whether the RCVLABEL flag is set on the socket - there may be many labels on a single message, to represent multiple hops through a network. Then, regular message parts can be consumed by checking the RCVMORE flag - these will be application level message parts. So, forwarding messages from XREP to XREQ in 3 will look like this (in PHP):

do {
        $message = $xrep->recv();
        $more = $xrep->getSockOpt(ZMQ::SOCKOPT_RCVMORE);
        if( $xrep->getSockOpt( ZMQ::SOCKOPT_RCVLABEL ) ) {
                $xreq->send( $message, ZMQ::MODE_SNDLABEL );
        } else {
                $xreq->send( $message, $more ? ZMQ::MODE_SNDMORE : 0 );
        }
} while( $more );

This does mean that while you'll be able to send a message back to where it came from, you can't blindly shoot a message to an XREP if you don't know the peer identity up front, which means that architectures will have to change slightly - for example, a service broker may send work to a worker via XREP in response to READY messages which contain the service types available on the worker, rather than sending to a peer with identity [WORKTYPE].

This is actually a great deal cleaner internally, as the labels can be passed all the way through devices to REP sockets, which can just transparently put them back onto their send stack for the response without bothering the user or requiring a delimiting message part.

You may also encounter references to ZeroMQ 4, and the ROUTER device. ZeroMQ 4 is the name for the experimental development branch of ZeroMQ, and while it does contain a new low level socket type, currently called ROUTER, that name may or may not stick. There is also no timescale or roadmap for when the experimental work might be released, or how it will related to ZeroMQ 3, so for the time being it is mainly of interest to those working on ZeroMQ core itself.

* - Or mostly, the fair queuing and load balancing is a bit more complex, but this will mostly work as expected.