Last time, we introduced ZeroMq and also talked about the fact that there was a native C# port by way of the NetMq library, which as I said we will be using from here on out. I also mentioned that the power of ZeroMq comes from a bunch of pre-canned sockets, which you can use as building blocks to build massive or small topologies.
From the ZeroMq guide, it states this:
The built-in core ØMQ patterns are:
- Request-reply, which connects a set of clients to a set of services. This is a remote procedure call and task distribution pattern.
- Pub-sub, which connects a set of publishers to a set of subscribers. This is a data distribution pattern.
- Pipeline, which connects nodes in a fan-out/fan-in pattern that can have multiple steps and loops. This is a parallel task distribution and collection pattern.
- Exclusive pair, which connects two sockets exclusively. This is a pattern for connecting two threads in a process, not to be confused with “normal” pairs of sockets.
There are of course certain well known patterns, that the chaps that wrote Zero have come across, and talk about in the book and the guide (links here again in case you missed them last time)
Book
Online Guide
I personally think it is a very clever thing to have done, to give certain sections of topologies an actual pattern name, as it means you can Google around a certain pattern name. For example, I may Google “Lazy Pirate Pattern C#”, and I would know that the results would almost certainly be talking about the exact socket arrangement I had in mind. So yeah, good idea giving these things names.
Standard ZeroMq Socket Types
Anyway, enough chit chat, let's get to the crux of what I wanted to talk about this time, which is the different socket types within ZeroMq.
Zero actual has the following socket types:
PUB
This is known as a PublisherSocket
in NetMq, and can be used to publish messages.
SUB
This is known as a SubscriberSocket
in NetMq, and can be used to subscribe to message(s) (you can fill in a subscription topic which indicates which published messages you care about).
XPUB
This is known as a XPublisherSocket
in NetMq and can be used to publish messages. XPUB and XSUB are used where you may have to bridge different networks.
XSUB
This is known as a XSubscriberSocket
in NetMq. and can be used to subscribe to message(s) (you can fill in a subscription topic which indicates which published messages you care about). XPUB and XSUB are used where you may have to bridge different networks.
REQ
This is known as a RequestSocket
in NetMq. Is a synchronous blocking socket, that would initiate a request message.
REP
This is known as a ResponseSocket
in NetMq. Is a synchronous blocking socket, that would provide a response to a message.
ROUTER
This is known as a RouterSocket
in NetMq. Router is typically a broker socket (but not limited to), and provides routing where it would more than likely know how to route messages back to the calling socket, thus its name of “Router
”. It is fully asynchronous (non blocking)
DEALER
This is known as a DealerSocket
in NetMq. Dealer is typically a worker socket, and doesn’t provide any routing (ie it doesn’t know about the calling sockets identity), but it is fully asynchronous (non blocking)
PUSH
This is known as a PushSocket
in NetMq. This would typically be used to push messages at worker, within a pipeline pattern.
PULL
This is known as a PullSocket
in NetMq. This would one part of a work within a pipeline pattern, which would pull from a PUSH
socket and the n do some work.
PAIR
This is known as a PairSocket
in NetMq.
Standard ZeroMq Socket Pairs
There are pretty strict recommendations about the pairing of the sockets we just discussed. The standard pairs of sockets that you should stick to using are shown below:
Any other combination will produce undocumented and unreliable results, and future versions of ZeroMq will probably return errors if you try them
PUB and SUB
A standard Pub/Sub arrangement
XPUB and XSUB
A standard Pub/Sub arrangement
REQ and RES
A standard synchronous request/response arrangement
The REQ client must initiate the message flow. A REP server cannot talk to a REQ client that hasn’t first sent it a request. Technically, it’s not even possible, and the API also returns an EFSM error if you try it.
REQ and ROUTER
A standard synchronous request with an asynchronous server responding, where the router will know how to do the routing back the correct request socket
In the same way that we can replace REQ with DEALER ….we can replace REP with ROUTER. This gives us an asynchronous server that can talk to multiple REQ clients at the same time. If we rewrote the “Hello World” server using ROUTER, we’d be able to process any number of “Hello” requests in parallel.
We can use ROUTER in two distinct ways:
- As a proxy that switches messages between frontend and backend sockets
- As an application that reads the message and acts on it
In the first case, the ROUTER simply reads all frames, including the artificial identity frame, and passes them on blindly. In the second case, the ROUTER must know the format of the reply envelope it’s being sent. As the other peer is a REQ socket, the ROUTER gets the identity frame, an empty frame, and then the data frame.
We will see more on what this means in subsequent posts.
DEALER and REP
An asynchronous request with a synchronous server responding. When we use a standard REQ (i.e., not a DEALER for the client) socket, it does one extra thing for us, which is to include an empty frame. So when we switch to using a Dealer
for the client, we need to do that part ourselves, by using SendMore
, which we will get into within the next post.
If we rewrote the “Hello World” client using DEALER, we’d be able to send off any number of “Hello” requests without waiting for replies.
When we use a DEALER to talk to a REP socket, we must accurately emulate the envelope that the REQ socket would have sent, or the REP socket will discard the message as invalid. So, to send a message, we:
- Send an empty message frame with the MORE flag set; then
- Send the message body.
And when we receive a message, we:
- Receive the first frame and if it’s not empty, discard the whole message;
- Receive the next frame and pass that to the application.
http://zguide.zeromq.org/page:all#toc59
DEALER and ROUTER
An asynchronous request with an asynchronous server responding, where the router will know how to do the routing back to the correct request socket.
With DEALER and ROUTER to get the most powerful socket combination, which is DEALER talking to ROUTER. It gives us asynchronous clients talking to asynchronous servers, where both sides have full control over the message formats.
Because both DEALER and ROUTER can work with arbitrary message formats, if you hope to use these safely, you have to become a little bit of a protocol designer. At the very least, you must decide whether you wish to emulate the REQ/REP reply envelope. It depends on whether you actually need to send replies or not.
DEALER and DEALER
An asynchronous request with an asynchronous server responding (this should be used if the DEALER
is talking to one and only one peer).
With a DEALER/DEALER, your worker can suddenly go full asynchronous, sending any number of replies back. The cost is that you have to manage the reply envelopes yourself, and get them right, or nothing at all will work. We’ll see a worked example later. Let’s just say for now that DEALER to DEALER is one of the trickier patterns to get right, and happily it’s rare that we need it.
ROUTER and ROUTER
An asynchronous request with an asynchronous server responding.
This sounds perfect for N-to-N connections, but it’s the most difficult combination to use. You should avoid it until you are well advanced with ØMQ.
PUSH and PULL
Push socket connected to a Pull, which you may see in a divide and conquer type arrangement.
PAIR and PAIR
- Pair sockets should ONLY talk to another pair, it is a well defined pair, Typically, you would use this for connecting two threads in a process.