
- ZeroMQ - Home
- ZeroMQ - Overview
- ZeroMQ - Installation
- ZeroMQ - Features
- ZeroMQ Messaging
- ZeroMQ - Socket Types
- ZeroMQ - Communication Patterns
- ZeroMQ - Transport Protocols
- ZeroMQ - Message Framing
- Scaling & Performance
- ZeroMQ - Load Balancing
- ZeroMQ - SMP
- ZeroMQ - Multithreading
- ZeroMQ - Performance Considerations
- ZeroMQ Useful Resources
- ZeroMQ - Quick Guide
- ZeroMQ - Useful Resources
- ZeroMQ - Discussion
ZeroMQ - Quick Guide
ZeroMQ - Overview
In this chapter, we are dedicated to knowing the details of ZeroMQ, such as its definition, usage, history, inventor, and development. Let us understand each section one by one.
What is ZeroMQ?
TheZeroMQis a lightweight open-source universal messaging library that enables asynchronous communication between distributed systems, applications, and services. It supplies a simple socket-like API which is used to create scalable, concurrent, and fault-tolerant architectures. It is written in C++.
Asynchronous communication between distributed systems: It is a method that works for message exchange where the sending and receiving processes operate independently and do not need to wait for each other to complete their tasks.
ZeroMQ supports common messaging patterns such as pub or sub, request or reply, and client or server. It also supports various protocols like TCP, in-process, inter-process, multi-cast, and web socket.
ZeroMQ Use Cases
It can be used as the fabric for the cluster products and is designed to simplify the development of the complex messaging pattern.
Who invented ZeroMQ?
ZeroMQ is an universal messaging library discovered in 2007 by Belgian software engineer Pieter Hintjens. Hintjens's goal in building ZeroMQ was to create a flexible, high-performance and easy-to-use messaging library. ZeroMQ has had a great role on the future of asynchronous communication, not only due to its architecture, but also because of Hintjens continuous improvement of the ZeroMQ library.
History & Evolution
Following is the history and evolution of ZeroMQ −
Early Days: 2007 - 2009
- ZeroMQ was invented in 2007 by Pieter Hintjens, a Belgian software developer.
- Initially, it was designed by iMatrix Corporation, a software company founded by Hintjens.
Rapid Growth: 20102012
- ZeroMQ gained popularity in the 2010s as a messaging library for distributed systems and cloud computing.
- It attracted a large community of contributors, and the library supported several programming languages, including Python, Java, and C-Sharp.
- ZeroMQ 2.0 was launched in 2010, introducing a new API and improved performance.
Founding of the ZeroMQ Organization: 2011
- The ZeroMQ organization was formed in 2011 to design and oversee the library.
- The organization established a governance model that ensured the project remained community-driven and open-source.
Expansion and Maturity: 2013 - 2016
- ZeroMQ 3.0 was launched in 2012, including a new security framework and improved support for WebSockets.
- The library continued to gain popularity with support from the following industries: Finance, Healthcare, and IoT.
- The ZeroMQ organization joined the Linux Foundation in 2014, ensuring the long-term sustainability of the project.
Recent Development: 2017 - Present
- ZeroMQ 4.0 was launched in 2017, featuring improved performance, security, and support for new protocols.
- ZeroMQ remains a popular choice for building distributed systems, cloud applications, and Internet of Things (IoT) solutions.
Throughout its development process, ZeroMQ has focused on ease of use, scalability, and flexibility, contributing to its support as a framework for building distributed systems, cloud applications, and IoT solutions.
ZeroMQ - Installation Setup
First step in the journey of learning ZeroMQ is to install the core ZeroMQ library on your system, and depending on the programming language you are using, you need to install the corresponding language bindings to interact with ZeroMQ in your code.
For example, if you are using Python language, you need to install the pyzmq, which provides the Python bindings for ZeroMQ.
ZeroMQ library is not dependent on the operating system for installation. Instead, it depends on the programming language and its respective binding dependencies. Therefore, the installation steps are generally similar across different operating systems.
How to setup ZeroMQ in Java?
The following instructions will explain how to install and set up the ZeroMQ library in Java. To install and use ZeroMQ (MQ) in Java, you need to use a Java binding for ZeroMQ. The most commonly used binding is JeroMQ, which is a pure Java implementation of ZeroMQ.
Here is the step-by-step guide to install ZeroMQ in Java −
Step 1: Create a Maven Project in Java
To create a Maven Project in Java, open your preferred IDE (we are using Eclipse), click on the File menu on the left-top corner, and choose Maven Project in the displayed list, as shown in the following image −

This will give you a "New Maven Project" window. In it, click on the Next button.

In the next window, enter "Apache" in the Filter text box, select quickstart and click on Next.

Then, enter "com.zeromq" in the GroupId text-box and "zeromq" in the ArtifactId text-box, then click Finish (You can choose any values for "GroupId" and "ArtifactId").

After clicking Finish enter 'y' in your terminal and press Enter.
Step 2: Add ZeroMQ Dependency
The simplest way to install ZeroMQ in a Java project is by using JeroMQ, which can be included as a dependency in your project.
If you are using Maven or Gradle (both are Java development tools) to manage your project, add the dependency to your pom.xml or build.gradle file.
<dependency> <groupId>org.zeromq</groupId> <artifactId>jeromq</artifactId> <version>0.5.3</version> </dependency> //for the latest SNAPSHOT --> <dependency> <groupId>org.zeromq</groupId> <artifactId>jeromq</artifactId> <version>0.6.0-SNAPSHOT</version> </dependency> //If you can't find the latest snapshot <repositories> <repository> <id>sonatype-nexus-snapshots</id> <url>https://oss.sonatype.org/content/repositories/snapshots</url> <releases> <enabled>false</enabled> </releases> <snapshots> <enabled>true</enabled> </snapshots> </repository> </repositories>
Step 3: Write Your First ZeroMQ Program in Java
Once JeroMQ is included in your project, you can start using it. Following is an example of a basic ZeroMQ publisher and subscriber in Java −
Publisher
The following is the basic example of the "Publisher" −
import org.zeromq.ZMQ; import org.zeromq.ZMQ.Context; import org.zeromq.ZMQ.Socket; public class Publisher { public static void main(String[] args) { Context context = ZMQ.context(1); Socket socket = context.socket(ZMQ.PUB); socket.bind("tcp://*:5555"); while (true) { socket.send("Hello, subscribers!".getBytes(), 0); } } }
Output
//it will simply send the message to the receiver
Subscriber
The following is the "Subscriber" example −
import org.zeromq.ZMQ; import org.zeromq.ZMQ.Context; import org.zeromq.ZMQ.Socket; public class Subscriber { public static void main(String[] args) { Context context = ZMQ.context(1); Socket socket = context.socket(ZMQ.SUB); socket.connect("tcp://localhost:5555"); socket.subscribe("".getBytes()); // Subscribe to all messages while (true) { byte[] message = socket.recv(0); System.out.println("Received message: " + new String(message)); } } }
Output
The above program displays all the receive messages, which is sent by "publisher" −
Received message: Hello, subscribers! Received message: Hello, subscribers! Received message: Hello, subscribers! Received message: Hello, subscribers! Received message: Hello, subscribers! Received message: Hello, subscribers!
How to setup ZeroMQ in Python?
To Download and install ZeroMQ in Python, we need to download the Python library that binds with ZeroMQ which is PyZMQ library, which is a fast and lightweight messaging library.
PyZMQ works with any reasonable version of Python that should be greater than or equal to 3.7, as well as PyPy. PyZMQ is used for message queuing without a message broker.
Step 1: Install PyZMQ
To install the PyZMQ we can use the pip, which is the most common way to install Python packages. The following are the steps:
Open the terminal and command prompt
- On the window, press window + R, type cmd, and hit enter.
- On Mac or Linux, open a terminal.
Run the pip install command
To install PyZMQ, run the following command in your terminal or command prompt:
pip install pyzmq
The above command will download and install the PyZMQ and the ZeroMQ libraries.
Downloading pyzmq-26.2.0-cp312-cp312-win_amd64.whl.metadata (6.2 kB) Downloading pyzmq-26.2.0-cp312-cp312-win_amd64.whl (637 kB) --------------------- 637.8/637.8 kB 5.8 MB/s eta 0:00:00 Installing collected packages: pyzmq Successfully installed pyzmq-26.2.0 [notice] A new release of pip is available: 24.0 -> 24.2 [notice] To update, run: python.exe -m pip install --upgrade pip
Step 2: Verification
To confirm that PyZMQ is installed correctly, open the Python shell and run the following command. If it prints the installed version of ZeroMQ and PyZMQ without any errors, the installation is successful.
>>> import zmq >>> print(zmq.zmq_version()) 4.3.5 >>> print(zmq.pyzmq_version()) 26.2.0 >>>
Step 3: Write your first ZeroMQ program in Python
As we have already installed the Python messaging library "PyZMQ", we can write a Python program using ZeroMQ.
Publisher
The following is the basic example of the "Publisher" −
import zmq import time # Create a ZeroMQ context context = zmq.Context() # Create a PUB socket socket = context.socket(zmq.PUB) socket.bind("tcp://*:5555") while True: # Send a message every second message = "Hello, ZeroMQ!" socket.send_string(message) print(f"Sent: {message}") time.sleep(1)
Output
Sent: Hello, ZeroMQ! Sent: Hello, ZeroMQ! Sent: Hello, ZeroMQ! Sent: Hello, ZeroMQ! Sent: Hello, ZeroMQ!
Subscriber
The following is the "Subscriber" example −
import zmq # Create a ZeroMQ context context = zmq.Context() # Create a SUB socket socket = context.socket(zmq.SUB) socket.connect("tcp://localhost:5555") # Subscribe to all messages (empty string as subscription) socket.setsockopt_string(zmq.SUBSCRIBE, "") while True: message = socket.recv_string() print(f"Received: {message}")
Output
Received: Hello, ZeroMQ! Received: Hello, ZeroMQ! Received: Hello, ZeroMQ! Received: Hello, ZeroMQ! Received: Hello, ZeroMQ!
ZeroMQ - Features
ZeroMQis also known as 0MQ, or ZMQ. It is a lightweight open-source messaging library, which provides a simple and organized way to implement messaging patterns in both web and mobile applications. Here, is the some of its key features −
Messaging Pattern
ZeroMQ has several messaging patterns including −
- Request-Response: It allows a client to send a request to the server and receive a response.
- Publish-Subscribe: It allows a publisher to send messages to multiple subscribers.
- Push-Pull: It allows a producer to push messages to multiple consumers.
- Pub-Sub with filtering: It allows subscribers to filter messages based on topic.
Socket Type
ZeroMQ has several socket type including:
- REQ: It is used to request a message pattern.
- REP: It is used to response a message pattern.
- PUB: It is used to publish a message pattern.
- SUB: It is used to subscriber a message pattern.
- PUSH: It is used to push a message pattern.
- PULL: It is also used to push a message pattern.
- PAIR: It is used to bidirectional communication between two peers.
- ROUTER: It is used to routing messages between multiple peers.
- DEALER: It is used to load balancing and routing messages between multiple peers.
Key Features
ZeroMQ has several key features including:
- Asynchronous I/O: To handle multiple connections simultaneously ZeroMQ uses asynchronous I/O.
- Message Queue: To handle messages that cannot be processed immediately ZeroMQ provides a message queue.
- High Performance: Due to its high performance ZeroMQ can handle thousands of messages per second because.
- Scalability: ZeroMQ is designed to scale horizontally so that it can handle a large number of connections.
- Multi Transport: ZeroMQ supports multiple transport protocols including TCP, UDP, and in-process.
- Multi Language: ZeroMQ has bindings for many languages including C, C++, Java, Python, etc.
Use Cases
We can use ZeroMQ in financial applications, distributed systems, or real-time data streams, irrespective of the field ZeroMQ offers performance and simplicity for even the complex messaging scenarios. Following is a list of the common usages of ZeroMQ −
- Real-time System: ZeroMQ requires low latency and high throughput messaging so that it is used in real-time systems.
- Distributed System: ZeroMQ requires communication between multiple nodes so that it is used in distributed systems.
- Cloud Computing: To provide scalable and fault-tolerance messaging ZeroMQ is used in Cloud computing.
- Big Data: To provide high-performance and scalable messaging ZeroMQ is used in Big Data processing.
ZeroMQ - Socket Types
In ZeroMQ, the Socket is a standard API (Application Programming Interface) for the network programming. That's why the ZeroMQ presents the familiar socket-based API's. One of the most interesting characteristics of ZeroMQ for developers is its use of different socket types to implement any messaging pattern.
Before discussing the socket types, it's important to first understand the concept of Messaging patterns. Understanding these patterns will provide clarity on how different sockets operate and are used in ZeroMQ.
Messaging Patterns
A Messaging pattern refers to the specific design and behavior of how messages are exchanged between different components of a distributed system using ZeroMQ sockets. ZeroMQ provides several built-in messaging patterns that satisfy various communication needs.
Following are the built-in core messaging patterns −
- Request-reply Messaging Pattern
- Pub-sub (Publish-subscribe) Messaging Pattern
- Pipeline Messaging Pattern
- Exclusive Pair Messaging Pattern
There are more ZeroMQ patterns that are still in draft state as follows −
- Client-server Messaging Pattern
- Radio-dish Messaging Pattern
Socket Types
The ZeroMQ messaging library provides several socket type that defines the semantics of the socket, including how it routes messages, and queues. Following is the list of messaging patterns and the sockets that belong to these patterns −

Request-reply pattern
- REQ Socket
- REP Socket
- Dealer Socket
- Router Socket
Publish-subscribe pattern
- PUB Socket
- SUB Socket
- XPUB Socket
- XSUB Socket
Pipeline pattern
- PUSH Socket
- PULL Socket
Exclusive pair pattern
- PAIR Socket
REQ Socket
The REQ is one of the initial socket types of the ZeroMQ messaging library comes under the synchronous flavors of the request-reply pattern. The request-reply pattern is designed for various kinds of service-oriented architectures.
The REQ socket is used by the client to send requests to and receive replies from a service. This type of socket allows only an altering sequence of sends and subsequent receive calls. It may connect to any number of REP or Router socket types..
Following is the summary of characteristics of the "REQ" Socket:
Characteristic | Description |
---|---|
Compatible peer sockets | REQ, DEALER |
Direction | Bidirectional |
Send/receive pattern | Receive, Send, Receive, Send ... |
Outgoing routing strategy | Fair-robin |
Incoming routing strategy | Last peer |
Action in mute state | Block |
REP Socket
The REP socket is used by the services to receive requests from send replies to a client. This socket type allows only an alternating sequence ofreceiveand subsequentsendcalls. If the original requester does not exist anymore the reply is silently discarded.
Following is the summary of characteristics of the "REP" Socket:
Characteristic | Description |
---|---|
Compatible peer sockets | REQ, DEALER |
Direction | Bidirectional |
Send/receive pattern | Receive, Send, Receive, Send ... |
Outgoing routing strategy | Fair-robin |
Incoming routing strategy | Last peer |
Dealer Socket
The DEALER socket type is a powerful and flexible messaging pattern used for building advanced communication patterns like request-reply, publish-subscribe, or other custom messaging schemes. It uses the "Round-Robin" algorithm to send and receive messages.
This socket works as an asynchronous replacement forREQ, for clients that communicate toREPorROUTERservers, and the messages received by aDEALERare fair-queued from all connected peers.
Following is the summary of characteristics of the "Dealer" Socket:
Characteristic | Description |
---|---|
Compatible peer sockets | ROUTER, REP, DEALER |
Direction | Bidirectional |
Send/receive pattern | Unrestricted |
Outgoing routing strategy | Round-robin |
Incoming routing strategy | Fair-queued |
Action in mute state | Block |
Router Socket
A ROUTER socket is one of the socket types used for advanced message routing patterns. It enables complex routing logic by allowing you to address messages to specific clients. ROUTERworks as an asynchronous replacement forREP, and is often used as the basis for servers that communicate toDEALERclients.
It can send messages to specific peers using an address, which is often an identity string.
This socket supports message framing, which means it can handle multi-part messages. Each message sent through a ROUTER socket can be composed of multiple parts, where the first part is often used as a routing address, and the following parts contain the actual data.
Following is the summary of characteristics of the "Dealer" Socket:
Characteristic | Description |
---|---|
Compatible peer sockets | DEALER, REQ, ROUTER |
Direction | Bidirectional |
Send/receive pattern | Unrestricted |
Outgoing routing strategy | See text |
Incoming routing strategy | Fair-queued |
Action in mute state | Drop (see text) |
PUB Socket
A PUB (publish) is one of the core socket types used by the publisher to distribute data referring to implementing the publish-subscribe messaging pattern. It is designed to send messages to multiple subscribers. This socket type is not able to receive any messages from the server.
Following is the summary of characteristics of the "PUB" Socket:
Characteristic | Description |
---|---|
Compatible peer sockets | SUB, XSUB |
Direction | Unidirectional |
Send/receive pattern | Send only |
Outgoing routing strategy | N/A |
Incoming routing strategy | Fan out |
Action in mute state | Drop |
SUB Socket
A SUB (Subscribe) is one of the socket types used by the subscriber to subscribe to the data distributed by the publisher. Initially, aSUBsocket is not subscribed to any messages.
Following is the summary of characteristics of the "SUB" Socket:
Characteristic | Description |
---|---|
Compatible peer sockets | PUB, XPUB |
Direction | Unidirectional |
Send/receive pattern | Receive only |
Outgoing routing strategy | Fair-queued |
Incoming routing strategy | N/A |
XPUB Socket
An XPUB (Extended Publish) socket is an advanced version of the PUB (Publish) socket used in the publish-subscribe messaging pattern. The XPUB socket provides additional features compared to a standard PUB socket.
Same asPUB, except that you can receive subscriptions from the peers in form of incoming messages. The subscription message is a byte 1 (for subscriptions) or byte 0 (for unsubscriptions) followed by the subscription body.
Following is the summary of characteristics of the "XPUB" Socket:
Characteristic | Description |
---|---|
Compatible peer sockets | ZMQ_SUB, ZMQ_XSUB |
Direction | Unidirectional |
Send/receive pattern | Send messages, receive subscriptions |
Outgoing routing strategy | N/A |
Incoming routing strategy | Fan out |
Action in mute state | Drop |
XSUB Socket
An XSUB (Extended Subscribe) socket is an advanced version of the SUB (Subscribe) socket used in the publish-subscribe messaging pattern. The XSUB socket provides additional features compared to a standard SUB socket.
Same asSUBexcept that you subscribe by sending subscription messages to the socket. The subscription message is a byte 1 (for subscriptions) or byte 0 (for non-subscriptions) followed by the subscription body.
Following is the summary of characteristics of the "XSUB" Socket:
Characteristic | Description |
---|---|
Compatible peer sockets | ZMQ_PUB, ZMQ_XPUB |
Direction | Unidirectional |
Send/receive pattern | Receive messages, send subscriptions |
Outgoing routing strategy | Fair-queued |
Incoming routing strategy | N/A |
Action in mute state | Drop |
PUSH Socket
APUSH socket is a type of socket that is designed for sending messages to one or more PULL sockets using a "round-robin" algorithm in a simple and scalable manner. Each connected PULL socket receives messages from the PUSH socket in a round-robin technique, ensuring that the workload is balanced among multiple receivers.
Following is the summary of characteristics of the "PUSH" Socket:
Characteristic | Description |
---|---|
Compatible peer sockets | PULL |
Direction | Unidirectional |
Send/receive pattern | Send only |
Outgoing routing strategy | N/A |
Incoming routing strategy | Round-robin |
Action in mute state | Block |
PULL Socket
APULLsocket is a type of socket that is designed for receiving messages using a "fair-queuing" algorithm in a simple and scalable manner. It is often used in conjunction with a PUSH socket, which sends messages to one or more PULL sockets.
Following is the summary of characteristics of the "PULL" Socket:
Characteristic | Description |
---|---|
Compatible peer sockets | PUSH |
Direction | Unidirectional |
Send/receive pattern | Receive only |
Outgoing routing strategy | Fair-queued |
Incoming routing strategy | N/A |
Action in mute state | Block |
PAIR Socket
A PAIR socket is a type of socket that belongs to the "Exclusive pair pattern". It is designed for a simple, one-to-one communication pattern and allows for a direct connection between two peers, providing a way for them to send messages back and onwards.
ZeroMQ - Communication Patterns
ZeroMQ is a high-performance, asynchronous messaging library that provides a set of communication patterns for generating distributed applications. It provides a simple and structured way to implement messaging patterns in various applications. Here are some basic core concepts of ZeroMQ −
- Sockets as Communication Endpoints: ZeroMQ sockets support advanced messaging patterns such as PUB-SUB and PUSH-PULL.
- Asynchronous Message Passing: ZeroMQ socket operates asynchronously, allowing applications to send and receive message without blocking.
- Scalability & Performance: ZeroMQ is designed to scale horizontally, allowing many-to-many configurations while maintaining high throughput and low latency.
Communication Patterns
The following is a list of communication patterns:
- Request-Reply (REQ-REP)
- Publish-Subscribe (PUB-SUB)
- Push-Pull (PUSH-PULL)
- Pair (PAIR)
- Dealer-Router (DEALER-ROUTER)
- Router-Dealer (ROUTER-DEALER)
- XPUB-XSUB
These communication patterns can be combined in various ways to create complicated distributed systems. ZeroMQ provides a flexible and scalable messaging framework that allows developers to implement anything from simple client-server configurations to complex distributed architectures.
Request-Reply
This is a remote service call and task distribution communication pattern that connects a group of clients to a group of services. This means that it is a simple client-server communication where the client sends a request to the server, and the server responds with a reply.
For example, consider a web server that responds to HTTP requests from clients.

Example
Following is an example of REQ/REP. First, we connect to the server and get responses from clients.
package com.zeromq.mavenProject; import org.zeromq.SocketType; import org.zeromq.ZMQ; import org.zeromq.ZContext; public class Practice { public static void main(String[] args) { try (ZContext context = new ZContext()) { System.out.println("Connecting to TP server"); // Socket to talk to server ZMQ.Socket socket = context.createSocket(SocketType.REQ); socket.connect("tcp://localhost:5555"); for (int requestNbr = 0; requestNbr != 5; requestNbr++) { String request = "Tutorialspoint"; System.out.println("Sending TP " + requestNbr); socket.send(request.getBytes(ZMQ.CHARSET), 0); byte[] reply = socket.recv(0); System.out.println( "Received " + new String(reply, ZMQ.CHARSET) + " " + requestNbr ); } } } }
Output
Connecting to TP server Sending TP 0 Received world 0 Sending TP 1 Received world 1 Sending TP 2 Received world 2 Sending TP 3 Received world 3 Sending TP 4 Received world 4
Publish-Subscribe
This is a data distribution communication pattern that links a group of publishers to a group of subscribers. It is used to broadcast messages to multiple recipients.
For example, consider a news feed system that broadcasts news articles to multiple subscribers.

Example
In this example, the publisher creates a PUB socket, binds to a port, and sends messages. A subscriber creates a SUB socket, connects to the publisher, receives messages, prints out those received messages.
// Publisher (PUB) class import org.zeromq.ZMQ; import org.zeromq.ZMQ.Context; import org.zeromq.ZMQ.Socket; // After running the PUB comment it runs SUB. public class PubSubPublisher { public static void main(String[] args) { Context context = ZMQ.context(1); Socket socket = context.socket(ZMQ.PUB); socket.bind("tcp://*:5555"); while (true) { socket.send("Hello, subscribers!".getBytes(), 0); } } } // Subscriber (SUB) class public class PubSubSubscriber { public static void main(String[] args) { Context context = ZMQ.context(1); Socket socket = context.socket(ZMQ.SUB); socket.connect("tcp://localhost:5555"); socket.subscribe("".getBytes()); // Subscribe to all messages while (true) { byte[] message = socket.recv(0); System.out.println("Received message: " + new String(message)); } } }
Output
Received message: Hello, subscribers! Received message: Hello, subscribers! Received message: Hello, subscribers! Received message: Hello, subscribers! Received message: Hello, subscribers! Received message: Hello, subscribers!
Push-Pull
This pattern is useful for load balancing and task distribution. The push socket sends messages to the pull socket, which receives and then processes the messages.
For example, consider a load balancer that distributes tasks to multiple worker nodes.

Example
In this example, the pusher creates a PUSH socket and connects to the puller. The puller creates a pull socket, binds it to the port, receives work items from the pusher, and prints them.
package com.zeromq.mavenProject; import org.zeromq.ZMQ; import org.zeromq.ZMQ.Context; import org.zeromq.ZMQ.Socket; // After running the PUSH comment it runs PULL. public class PushPullPusher { public static void main(String[] args) { // Create a PUSH socket and connect to the puller Context context = ZMQ.context(1); Socket socket = context.socket(ZMQ.PUSH); socket.connect("tcp://localhost:5500"); // Send work items to the puller while (true) { socket.send("Work item".getBytes(), 0); } } } public class PushPullPuller { public static void main(String[] args) { // Create a PULL socket and bind it to a port Context context = ZMQ.context(1); Socket socket = context.socket(ZMQ.PULL); socket.bind("tcp://*:5500"); // Receive work items from the pusher while (true) { byte[] message = socket.recv(0); System.out.println("Received work item: " + new String(message)); } } }
Output
Pair
This pattern can be used in simple peer-to-peer interactions. A pair of sockets are connected with each other in a peer-to-peer fashion so that two nodes can communicate bidirectionally.
For example, consider a chat application that allows two users to communicate each-other.

Example
In this example, we demonstrate the PAIR pattern by creating two nodes that can send and receive messages to each other. We are checking whether the connection is bidirectional or asynchronous. If yes, each node waits for the other node to respond before sending the next message.
package com.zeromq.mavenProject; import org.zeromq.ZMQ; import org.zeromq.ZMQ.Context; import org.zeromq.ZMQ.Socket; // After running the PairNode1 comment it runs PairNode2. public class PairNode1 { public static void main(String[] args) { // Create a PAIR socket and bind it to a port Context context = ZMQ.context(1); Socket socket = context.socket(ZMQ.PAIR); socket.bind("tcp://*:5000"); // Receive messages from Node 2 and send responses while (true) { byte[] message = socket.recv(0); System.out.println("Received message: " + new String(message)); socket.send("Hello, Node 2!".getBytes(), 0); } } } public class PairNode2 { public static void main(String[] args) { // Create a PAIR socket and connect to Node 1 Context context = ZMQ.context(1); Socket socket = context.socket(ZMQ.PAIR); socket.connect("tcp://localhost:5000"); // Send messages to Node 1 and receive responses while (true) { socket.send("Hello, Node 1!".getBytes(), 0); byte[] message = socket.recv(0); System.out.println("Received response: " + new String(message)); } } }
Output
Received message: Hello, Node 1! Received message: Hello, Node 1! Received message: Hello, Node 1! Received message: Hello, Node 1! Received message: Hello, Node 1!
Dealer-Router
This pattern used to implement complex distributed systems. A dealer socket sends messages to a router socket, which dispatches them to one or more connected peers.
For example, consider a distributed database system that routes queries to multiple nodes.
Router-Dealer
This pattern helps in implementing complex distributed systems. A router socket routes messages from one or more connected dealer sockets, each sending it to its respective peer.
For example, consider a content delivery network that routes to multiple edge servers.
XPUB-XSUB
This communication pattern is useful in creating dynamic publish-subscribe systems. XPUB is a special publisher that allows subscribers to connect and disconnect dynamically. XSUB is a special subscriber, which can connect to multiple publishers.
For example, consider a real-time analytics system where multiple publishers send data to multiple subscribers.
ZeroMQ - Transport Protocols
The transport protocol in ZeroMQ is known as the ZeroMQ Message Transport Protocol (ZMTP). It is a transport layer protocol for exchanging messages between two hosts over a connected transport layer such as Transmission Control Protocol (TCP).
TCP is the main protocol in the Internet protocol suite, often referred to as TCP/IP. TCP allows us to use two hosts or devices to connect and exchange data streams.

Here are some of the key features of ZMTP:
- Security: ZMTP supports extensible security mechanisms. Peers agree on the security mechanism and version by exchanging data and persisting or closing the connection.
- Backward Interoperability: ZMTP defines rules for backward interoperability.
- Command and Messaging Framing: ZMTP defines rules for command and message framing.
- Connection Metadata: ZMTP defines rules for connection metadata.
ZeroMQ supports several transport protocols that manage the exchange of messages between endpoints. Here are the primary transport protocols used in ZeroMQ:
TCP (Transmission Control Protocol)
It is the most reliable connection-oriented protocol that ensures that all messages are delivered in the correct order without duplication. This is typically used when processes are communicating over a network, whether on the same machine or on different machines.
Bind Example (Server):
// Bind to all available network interfaces on port 5555 socket.bind("tcp://*:5555")
Connect Example (Client):
// Connect to a remote server on the specified IP and port socket.connect("tcp://192.168.0.1:5555")
Advantages
Following are the advantages of using TCP in ZeroMQ −
- It is widely supported across all platforms and devices.
- It has reliable message delivery.
- It ensures that messages are received in order.
Disadvantages
Following are the disadvantages of using TCP in ZeroMQ −
- It has higher latency compared to other protocols like Inter-Process Communication (IPC).
- It also has more overhead from error checking, flow control, and acknowledgement packets.
IPC (Inter Process-Communication)
IPC allows communication between different processes on the same machine. It is better than TCP because it avoids network stack overhead by operating directly at the operating system level.
Bind Example (Server):
// Bind to a local file-based endpoint socket.bind("ipc:///tmp/zeromq-ipc")
Connect Example (Client):
// Connect to a local endpoint on the same machine socket.connect("ipc:///tmp/zeromq-ipc")
Advantages
Following are the advantages of using IPC in ZeroMQ −
- It is much faster than network-based protocols like TCP.
- There is no network latency since it works on the same machine.
- It is ideal for communication between different processes in the same application or microservices on the same server.
Disadvantages
Following are the disadvantages of using IPC in ZeroMQ −
- It is limited to communication between processes on the same machine.
- It cannot be used for communication between different machines
Inproc (In-Process)
Inproc is used for communication between threads within the same process. It is the fastest ZeroMQ transport because it avoids interprocess communication, relying only on memory transfers within the same application.
Bind Example (Thread 1):
// Bind to an in-process endpoint socket.bind("inproc://some-endpoint")
Connect Example (Thread 2):
// Connect to the in-process endpoint from another thread socket.connect("inproc://some-endpoint")
Advantages
Following are the advantages of using Inproc in ZeroMQ −
- It is the fastest transport as it does not involve any networking or process limitations.
- It supports communication between threads within the same application.
Disadvantages
Following are the disadvantages of using Inproc in ZeroMQ −
- It is not suitable for communication between different processes or across a network.
- It is limited to inter-thread communication within a single process.
PGM/EPGM
The PGM/EPGM (Pragmatic General Multicast/Encapsulated Pragmatic General Multicast) is used for applications that require reliable multicast delivery, such as real-time data delivery or live streaming. These protocols enable multicast communications, where a sender sends messages to multiple receivers simultaneously.
PGM: This is native multicast and requires network layer support. It is not available on all network infrastructures.
EPGM: ZeroMQ wraps PGM over UDP (encapsulation), allowing multicast to work on networks that do not directly support PGM.
Bind Example (Server):
// Bind to a multicast address and port socket.bind("epgm://eth0;239.192.1.1:5555")
Connect Example (Client):
// Connect to the multi-cast group socket.connect("epgm://239.192.1.1:5555")
Advantages
Following are the advantages of using PGM/EPGM in ZeroMQ −
- It is efficient for scenarios where one message needs to reach multiple clients (e.g., stock ticker updates, live sports scores).
- It minimizes network bandwidth by sending one message to multiple subscribers.
Disadvantages
Following are the disadvantages of using PGM/EPGM in ZeroMQ −
- It is more complex than unicast-based protocols like TCP.
- PGM is not widely supported and may require special network configuration.
UDP (User Datagram Protocol)
UDP is a connectionless and unreliable protocol that can be faster than TCP but does not guarantee message delivery or ordering. While, ZeroMQ does not directly support raw UDP as a transport (unlike TCP), it can be used indirectly via PGM or other protocols.
TIPC (transparent Inter Process-Communication)
TIPC is a transport protocol designed for efficient communication between nodes in a cluster. It is present in the Linux operating system and is optimized for high-speed inter-process communication within a cluster of machines.
Bind Example (Server):
// Bind to a TIPC service and instance socket.bind("tipc://{service,instance}")
Connect Example (Client):
// Connect to a TIPC service on the cluster socket.connect("tipc://{service,instance}")
Advantages
UDP is efficient for communication and high-speed transport design in cluster environments, especially for Linux clusters.
Disadvantages
Following are the disadvantages of using UDP in ZeroMQ −
- It is limited to Linux environments with TIPC support.
- It may require additional network setup to be used effectively.
In summary, each protocol has its strengths and weaknesses, and your choice will depend on the architecture of your system, performance requirements, and the environment in which your applications process.
ZeroMQ - Message Framing
Understanding Messages in ZeroMQ
A Message in ZeroMQ is a discrete data unit that is passed between applications or components of the same application. From ZeroMQ's point of view, messages are considered opaque binary data.
They are blocks of data sent and received over the network using various message patterns supported by ZeroMQ. ZeroMQ provides several message patterns as follows −
- PUB/SUB (Publish/Subscribe)
- REQ/REP (Request/Reply)
- PUSH/PULL
- Router/Dealer
Message Framing
The ZeroMQ messaging library refers to the structure and organization of messages exchanged between applications or services. The messaging framework provides a way to construct, send, and receive messages, and ensuring that messages are properly formatted, routed, and processed by the receiving application.
Here is a simple diagram to demonstrates how ZeroMQ frames messages −

Here,
- Socket: The Socket handles communication over the network. It sends and receives messages and manages the framing internally.
- Queue: It represents the internal mechanism that ZeroMQ uses to store and manage messages and their frames. It ensures that messages are processed correctly, even if split into multiple frames.
- Message: It is a logical unit of data composed of one or more frames.
- Frame: The individual data chunks that make up a message. Frames are sent and received in order, and reassembled into complete messages by ZeroMQ.
How Messages are Managed and Structured?
In ZeroMQ, the concepts of Envelope, Body, and Frames are important for understanding how messages are structured and managed:
- Envelope
- Body
- Frames
Envelope
In ZeroMQ, the term envelope is often used in the context of the ROUTER socket. An envelope generally includes metadata such as routing information, which routes messages to the correct receiver. It is more commonly associated with ROUTER sockets, where the envelope consists of the message routing identity and other metadata.
Body
The body of the message in ZeroMQ refers to the actual data being sent. This is the payload of the message that the application processes. The body is the main content being transmitted between sockets.
Frames
The concept of frames is relevant when dealing with more complex socket types like STREAM and ROUTER. Messages can be split into multiple frames, where each frame is a chunk of data that together forms the complete message. This is useful for handling large messages or messages with multiple parts.
ZeroMQ itself does not define or implement specific types of message framing as some protocols do. Instead, ZeroMQ provides a flexible messaging system where the framing and serialization of messages are handled by the application. However, it provides several messaging patterns and socket types that implicitly handle message framing in different ways. They are −
Publish/Subscribe (PUB/SUB)
- Publisher (PUB) - Sends messages to multiple subscribers.
- Subscriber (SUB - Receives messages based on subscription filters.
- Framing - ZeroMQ handles the framing internally, but messages are published as they are.
Request/Reply (REQ/REP)
- Request (REQ) - Sends a request to a reply socket and waits for a response.
- Reply (REP) - Receives requests and sends responses.
- Framing - ZeroMQ frames messages as discrete entities, maintaining the request and response protocol.
DEALER and ROUTER
- Dealer (DEALER) - Acts as a non-blocking requester, and able to handle multiple requests simultaneously.
- Router (ROUTER) - Handles messages in a more complex way, routing them based on identity or other criteria.
- Framing - Messages include routing metadata or identifiers, and ZeroMQ frames messages with this metadata for routing.
PUSH and PULL
- Push (PUSH) - Sends messages to a pull socket, generally used for distributing tasks.
- Pull (PULL) - Receives messages from a push socket.
- Framing - Messages are distributed in a round-robin technique, with ZeroMQ handling the framing internally.
Delivery Guarantees
ZeroMQ does not provide a built-in guarantee of message delivery, and there is no automatic retry mechanism in ZeroMQ. If a message is sent and the receiver is not available or there is a network failure, the message may be lost.
ZeroMQ - Synchronous Message Processing
The ZeroMQ is a high-performance asynchronous universal messaging library used for building distributed or concurrent applications. It is also known as MQ. As we know that ZeroMQ is primarily designed for asynchronous message passing, you can also implement synchronous message processing patterns using various socket types and messaging patterns.
Key Concepts
The following are important topics that you should know while performing synchronous message processing in ZeroMQ −
Socket: In ZeroMQ, a socket is an endpoint (API) for sending or receiving data between client and server. It represents a communication channel between two components (such as processes or devices) that allows them to exchange data. ZeroMQ provides different types of sockets for various messaging patterns such as PUB/SUB, REQ/REP, PUSH/PULL, etc.
Messaging Queuing: The ZeroMQ sockets are used to send and receive messages. They dont require a dedicated message broker, as the messaging patterns are implemented in the library itself, which makes it "broker less".
Asynchronous Nature: The ZeroMQ is primarily designed as asynchronous, which means it is designed to handle multiple operations at once, which is why it is often used for high-performance, non-blocking communication.
Here is the diagram of Synchronous Message Processing −

Implementing Synchronous Processing
The synchronous process is a type of operation where tasks or operations are executed sequentially, with each step or action waiting for the previous one to complete before proceeding.
To achieve synchronous processing with ZeroMQ, which follows an asynchronous mechanism by default, you can use specific patterns and socket types. The most common approach for synchronous message processing is using the REQ (request) and REP (reply) sockets, which follow a request-reply pattern. In the REQ/REP request pattern −
- REQ Socket: It is used by client to send request or data to the server.
- REP Socket: It is used by server to respond to received request.
Synchronous Message Processing in Java
Here is a basic example of synchronous message processing using ZeroMQ in Java −
Server code (REP Socket)
import org.zeromq.ZContext; import org.zeromq.SocketType; import org.zeromq.ZMQ; import org.zeromq.ZContext; public class Response { public static void main(String[] args) { try (ZContext context = new ZContext()) { ZMQ.Socket socket = context.createSocket(ZMQ.REP); socket.bind("tcp://127.0.0.1:5555"); while (true) { // Wait for the next request from the client String message = socket.recvStr(); System.out.println("Received request: " + message); // Send a reply back to the client socket.send("Welcome, " + message); } } } }
Client code (REQ Socket)
import org.zeromq.ZContext; import org.zeromq.SocketType; import org.zeromq.ZMQ; import org.zeromq.ZContext; public class Request { public static void main(String[] args) { ZMQ.Context context = ZMQ.context(1); ZMQ.Socket socket = context.socket(ZMQ.REQ); socket.connect("tcp://127.0.0.1:5555"); // Send a request socket.send("to World".getBytes(ZMQ.CHARSET), 0); // Receive the reply byte[] reply = socket.recv(0); System.out.println("Received reply: "+new String(reply,ZMQ.CHARSET)); socket.close(); context.term(); } }
Output
After executing the above programs, the following output will be displayed −
Received reply: Welcome, to World
Synchronous Message Processing in Python
Here is a basic example of synchronous message processing using ZeroMQ in Python −
Server code (REP Socket)
import zmq def main(): context = zmq.Context() socket = context.socket(zmq.REP) socket.bind("tcp://127.0.0.1:5555") while True: # Wait for the next request from the client message = socket.recv_string() print(f"Received request: {message}") # Send a reply back to the client socket.send_string(f"Welcome, {message}") if __name__ == "__main__": main()
Client code (REQ Socket)
import zmq def main(): context = zmq.Context() socket = context.socket(zmq.REQ) socket.connect("tcp://127.0.0.1:5555") # Send a request socket.send_string("to World") # Receive the reply message = socket.recv_string() print(f"Received reply: {message}") if __name__ == "__main__": main()
Output
The above programs produces the following output −
Received reply: Welcome, to World
ZeroMQ - Multithreading
A multi-threading is a technique that allows to perform multiple tasks at a time within the same application, and it can be used with ZeroMQ to handle tasks over multiple threads simultaneously.
In the previous chapters, we had already discussed that ZeroMQ is a high-performance messaging library that provides several messaging patterns, such as publish-subscribe, request-reply, and more, to completely use ZeroMQ in a multi-threaded environment, you must consider several important characteristics.
Thread Safety
It is designed to be thread-safe, which means you can use ZeroMQ sockets in multiple threads without running into data corruption or race condition problems. It is important to ensure that the application code that interacts with ZeroMQ follows thread safety principles.
Socket access
The sockets in ZeroMQ are used to manage and enable communication between different parts of a distributed application. As they are thread-safe, so it is recommended to avoid sharing sockets between threads if not necessary. Instead, each thread should work with its own set of sockets to prevent potential problems and simplify code maintenance.
Context Management
The context in ZeroMQ is used to manage the state of the library and is created once in each application. The context is thread-safe, so you can share it between threads. However, you should make sure that you do not create multiple contexts unnecessarily, as a single context can manage all the sockets efficiently.
Message Handling
When working with message processing in a multi-threaded environment, make sure the message handling logic is develop to handle concurrent access. This is usually involves using synchronization primitives such as mutexes or locks where necessary.
Concurrency Pattern
ZeroMQ provides various concurrency patterns to facilitate scalable and efficient message processing in distributed systems. Depending on your application needs, you can choose different concurrency patterns such as producer-consumer, work-stealing, etc. The ZeroMQ messaging library allows you to implement these patterns in a multi-threaded context.
Diagram of Multi-threading
The following diagram illustrates multi-threading in ZeroMQ, it shows how multiple threads interact with ZeroMQ sockets to manage concurrent communication. This can be useful for understanding how different threads can handle messaging tasks simultaneously −

In the above diagram you can observe two layers namely −
- Application Layer: It represents the main application that managing multiple threads and ZeroMQ sockets.
- Threads: You can observe three threads (Thread 1, Thread 2, Thread 3).
Where −
- Thread 1: The thread1 handles a PUB (Publisher) socket and a REP (Replier) socket.
- Thread 2: The thread2 manages a SUB (Subscriber) socket and a PUSH (Pusher) socket.
- Thread 3: The thread3 operates a PULL (Puller) socket and a DEALER (Dealer) socket.
ZeroMQ - Performance Considerations
In general, performance considerations are as important as the success of applications and cloud-based solutions.
There are several points that we should keep in mind to optimize the performance of ZeroMQ (ZMQ). ZeroMQ is considered a high-performance, asynchronous messaging library, but we must consider both hardware and software factors to make the most use of it.
The following are the number of factors that affect the ZeroMQPerformance −
- Memory Usage
- Latency
- Throughput
- Stack
Let's discuss the above factors in detail −
Memory Usage
ZeroMQ is considered to be used as thin as possible, so that it can run even in a platforms having limited memory. The low memory footprint is also important to optimize the use of the L1i cache. When the code size is small enough the processor can keep the entire messaging code in the L1i cache and avoid slow accesses to physical memory to get new parts of the code.
The part of the library holding the actual code is 80kB long and the shared library is about 350kB on Linux platforms. Still, a lot of the code is inline, so it is placed as inline functions in header files rather than in libraries.
The following tables shows the memory usage as reported by top utility −
Application | Virtual Memory | Resident Memory | Resident Code |
---|---|---|---|
Sender | 24312kB | 1360kB | 12kB |
Receiver | 24308kB | 1360kB | 8kB |
Latency
Latency indicates the time delay between a cause and its effect, usually in a communication system or process. In the context of computing and networking, latency measures the time it takes for data to travel from one point to another or for a system to respond to an action.
We have latency measured of 40 microseconds for 1-byte messages, with the networking stack taking 25 microseconds and ZeroMQ taking 15 microseconds. Using 10GbE at a TCP latency of 15 microseconds, we would expect latency to be around 30 microseconds. We also have a solution in which we bypass the OS kernel to talk directly to the hardware which aims to reduce the latency below 20 microseconds.
Low latency: If low latency is very important, the ZMQ_IMMEDIATE socket option should be used to prevent any buffering. It is also advisable to use in-proc (in memory messaging between thread) or inter process communication sockets instead of TCP since they are less costly.
Throughput
Throughput is nothing but the rate at which at which ZeroMQ sends and receives messages over a network. This is measured in message per second (mps) or even data volume per second (mb/s).
Throughput is affected by the following factors, including message size, socket types, network bandwidth, and system performance.
- Message Size: The larger message reduce the rate of message sent per second, while smaller message increase it.
- Socket type: The socket types push-pull or pub-sub can impact how message are distributed and how fast they are processed.
- Batching: Sending message in batches reduces overhead and increase the throughput.
- Network Bandwidth: The higher bandwidth allows more data to flow through, improving the throughput.
- System Resources: CPU, memory, and thread utilization affect how efficiently messages are processed.
Stack
In ZeroMQ, the stack refers to the layers of software and components required to send and receive messages. The entire stack, including network devices, NICs, processors, and operating systems, can affect results.It is generally composed of −
Application Layer
It is a layer where our application code interacts with ZeroMQ using its API. We define how messages are sent and received between different sockets (PUB-SUB, PUSH-PULL, etc.).
Messaging Layer
This layer manages message queuing, dispatch and routing based on the socket pattern we choose such as REQ-REP, PUB-SUB. It handles message buffering, batching, and flow control.
Transport Layer
This layer decides how to deliver a message depending on the chosen transport protocols. The following are the transport protocols:
- inproc: It is an in-process communication (threads within the same process).
- ipc: It is an inter-process communication (process on the same machine).
- tcp: It is used to communicate over a TCP network.
- pgm/epgm: It is a multicast transport protocol for broadcast.
Network Stack
ZeroMQ uses a system's networking layer like TCP/IP, which handles lower-level tasks such as packet transmission, retransmission in the case of TCP, and congestion control.
Hardware
The physical hardware, including the network interface, drives the actual transmission and receipt of the message.