2 minute read

ZeroMQ is a high-performance messaging library that makes it easy to build distributed applications.

In this tutorial, we’ll use ZeroMQ to create a simple publisher-subscriber model-based chat application in Python that allows users to send messages to each other in real-time.

First, let’s install the PyZMQ library.

pip install pyzmq

Server and Client Codes

Let’s first create a client using the library to create a chat application using the Request-Reply messaging pattern. In the following example let’s use port $5000$.

# client.py
import zmq
context = zmq.Context()

# Create a socket to send messages to the server
socket = context.socket(zmq.REQ)
socket.connect("tcp://localhost:5000")

while True:
    message = input("me: ")
    socket.send_string(message)

    # Wait for the server's response
    response = socket.recv_string()
    print("Alice:", response)

Here’s the code for the server:

# server.py
import zmq
context = zmq.Context()

# Create a socket to receive messages from the client
socket = context.socket(zmq.REP)
socket.bind("tcp://*:5000")

while True:
    # Wait for a message from the client
    message = socket.recv_string()
    print("Bob:", message)

    # Send a response back to the client
    response = input("Me: ")
    socket.send_string(response)

Now, we need to open to terminal tabs/windows. And run one of the following in each.

(venv)$ python server.py
(venv)$ python client.py

Chat Application for Multiple users

To allow multiple people to participate in the chat, we can use the Publish-Subscribe messaging pattern.

In this pattern, each person acts as a publisher, publishing messages to a single topic, and a subscriber, subscribing to messages on that topic.

Publisher Code

# publisher.py
import zmq
context = zmq.Context()

# Create a socket to publish messages to the subscribers
socket = context.socket(zmq.PUB)
socket.bind("tcp://*:5555")

while True:
    message = input("You: ")
    socket.send_string(message)

Subscriber Code

# subscriber.py
import zmq
context = zmq.Context()

# Create a socket to subscribe to messages from the publisher
socket = context.socket(zmq.SUB)
socket.connect("tcp://localhost:5555")
socket.setsockopt_string(zmq.SUBSCRIBE, "")

while True:
    # Wait for a message from the publisher
    message = socket.recv_string()
    print(message)

Now, let’s start the publisher (person 1) in one terminal window

(venv)$ python publisher.py

And then start the subscribers (person 2+) in separate terminal windows:

(venv)$ python subscriber.py

Please note that, in this example, we’re using the default topic, which is an empty string. If you want to use a specific topic, you can specify it using the socket.setsockopt_string(zmq.SUBSCRIBE, "<topic>") method on the subscriber socket, and the socket.send_string(message, zmq.SNDMORE) method on the publisher socket, where "<topic>" is the name of the topic we want to use.

Here’s one issue though. Only the publisher can send message and every subscriber only listens. If we want all users to interact simulatneously, we need a Push-Pull pattern, we have multiple “pushers” and multiple “pullers.” The pushers send messages to a queue, and the pullers receive messages from the same queue.

Final Code

Let’s use thread to handle subscribe and publish at the same time.

# user.py
import zmq
import threading

def subscriber():
    context = zmq.Context()
    socket = context.socket(zmq.PULL)
    socket.connect("tcp://localhost:5005")
    while True:
        message = socket.recv_string()
        print(message)

def publisher():
    context = zmq.Context()
    socket = context.socket(zmq.PUSH)
    socket.bind("tcp://*:5005")
    while True:
        message = input()
        socket.send_string(message)

if __name__ == "__main__":
    threading.Thread(target=subscriber).start()
    publisher()

Now we need to run user.py in different terminal tabs/windows based on how many users we want.

Note that, here, the subscriber listens for messages from the socket and prints them to the console, while the publisher waits for user input and sends the input as a message to the socket.

Concluding Remarks

This is not a full-functional chat application. I just wanted to explore zeroMQ and the first thing came to mind was a chat application as this library provides messaging system across distributed systems.

That’s all for today! Cheers!!! 😎

Leave a comment