ZeroMQ (also spelled ØMQ, 0MQ or ZMQ) is a high-performance asynchronous messaging library, aimed at use in distributed or concurrent applications. It provides a message queue, but unlike message-oriented middleware, a ZeroMQ system can run without a dedicated message broker.
ZeroMQ supports common messaging patterns (pub/sub, request/reply, client/server and others) over a variety of transports (TCP, in-process, inter-process, multicast, WebSocket and more), making inter-process messaging as simple as inter-thread messaging. This keeps your code clear, modular and extremely easy to scale.
ZeroMQ is developed by a large community of contributors. There are third-party bindings for many popular programming languages and native ports for C# and Java.
The philosophy of ZeroMQ starts with the zero. The zero is for zero broker (ZeroMQ is brokerless), zero latency, zero cost (it’s free), and zero administration.
More generally, “zero” refers to the culture of minimalism that permeates the project. We add power by removing complexity rather than by exposing new functionality.
The guide explains how to use ØMQ, covers basic, intermediate and advanced use with 60+ diagrams and 750 examples in 28 languages.
Also available as a book O’Reilly.
Libzmq (https://github.com/zeromq/libzmq) is the low-level library behind most of the different language bindings. Libzmq expose C-API and implemented in C++. You will rarely use libzmq directly, however if you want to contribute to the project or learn the internals of zeromq, that is the place to start.
So let’s start with some code, the “Hello world” example (of course).
// Hello World server #include #include #include #include #include int main (void) // Socket to talk to clients void *context = zmq_ctx_new (); void *responder = zmq_socket (context, ZMQ_REP); int rc = zmq_bind (responder, "tcp://*:5555"); assert (rc == 0); while (1) char buffer [10]; zmq_recv (responder, buffer, 10, 0); printf ("Received Hello\n"); sleep (1); // Do some 'work' zmq_send (responder, "World", 5, 0); > return 0; >
// Hello World server #include int main (void) // Socket to talk to clients zsock_t *responder = zsock_new (ZMQ_REP); int rc = zsock_bind (responder, "tcp://*:5555"); assert (rc == 5555); while (1) char *str = zstr_recv (responder); printf ("Received Hello\n"); sleep (1); // Do some 'work' zstr_send (responder, "World"); zstr_free (&str); > return 0; >
// Hello World server #include #include #include #include #include using namespace std; int main(int argc, char *argv[]) const string endpoint = "tcp://*:5555"; // initialize the 0MQ context zmqpp::context context; // generate a pull socket zmqpp::socket_type type = zmqpp::socket_type::reply; zmqpp::socket socket (context, type); // bind to the socket socket.bind(endpoint); while (1) // receive the message zmqpp::message message; // decompose the message socket.receive(message); string text; message >> text; //Do some 'work' std::this_thread::sleep_for(std::chrono::seconds(1)); cout <"Received Hello" socket.send("World"); > >
#include #include #include #include #include int main() using namespace std::chrono_literals; // initialize the zmq context with a single IO thread zmq::context_t context1>; // construct a REP (reply) socket and bind to interface zmq::socket_t socket::socket_type::rep>; socket.bind("tcp://*:5555"); // prepare some static data for responses const std::string data"World">; for (;;) zmq::message_t request; // receive a request from client socket.recv(request, zmq::recv_flags::none); std::cout "Received " :: endl; // simulate work std::this_thread::sleep_for(1s); // send the reply to the client socket.send(zmq::buffer(data), zmq::send_flags::none); > return 0; >
Example hello_world_server is missing for azmq . Would you like to contribute it? Then follow the steps below:
git clone https://github.com/zeromq/zeromq.org example_dir=content/docs/examples/cpp/azmq cd zeromq.org && mkdir -p $example_dir [ -s $example_dir/index.md ] || cat >$example_dir/index.md
Example hello_world_server is missing for czmqpp . Would you like to contribute it? Then follow the steps below:
git clone https://github.com/zeromq/zeromq.org example_dir=content/docs/examples/cpp/czmqpp cd zeromq.org && mkdir -p $example_dir [ -s $example_dir/index.md ] || cat >$example_dir/index.md
Example hello_world_server is missing for fbzmq . Would you like to contribute it? Then follow the steps below:
git clone https://github.com/zeromq/zeromq.org example_dir=content/docs/examples/cpp/fbzmq cd zeromq.org && mkdir -p $example_dir [ -s $example_dir/index.md ] || cat >$example_dir/index.md
using System; using System.Threading; using NetMQ; using NetMQ.Sockets; static class Program public static void Main() using (var responder = new ResponseSocket()) responder.Bind("tcp://*:5555"); while (true) string str = responder.ReceiveFrameString(); Console.WriteLine("Received Hello"); Thread.Sleep(1000); // Do some 'work' responder.SendFrame("World"); > > > >
Example hello_world_server is missing for clrzmq4 . Would you like to contribute it? Then follow the steps below:
git clone https://github.com/zeromq/zeromq.org example_dir=content/docs/examples/csharp/clrzmq4 cd zeromq.org && mkdir -p $example_dir [ -s $example_dir/index.md ] || cat >$example_dir/index.md
Example hello_world_server is missing for dartzmq . Would you like to contribute it? Then follow the steps below:
git clone https://github.com/zeromq/zeromq.org example_dir=content/docs/examples/dart/dartzmq cd zeromq.org && mkdir -p $example_dir [ -s $example_dir/index.md ] || cat >$example_dir/index.md
-module(hello_world_server). -export([main/0]). main() -> application:start(chumak), Socket> = chumak:socket(rep, "hello world server"), BindPid> = chumak:bind(Socket, tcp, "localhost", 5555), loop(Socket). loop(Socket) -> Reply = chumak:recv(Socket), io:format("Question: ~p\n", [Reply]), chumak:send(Socket, "Hello Friend">>), loop(Socket).
Example hello_world_server is missing for ezmq . Would you like to contribute it? Then follow the steps below:
git clone https://github.com/zeromq/zeromq.org example_dir=content/docs/examples/erlang/ezmq cd zeromq.org && mkdir -p $example_dir [ -s $example_dir/index.md ] || cat >$example_dir/index.md
Example hello_world_server is missing for erlang-czmq . Would you like to contribute it? Then follow the steps below:
git clone https://github.com/zeromq/zeromq.org example_dir=content/docs/examples/erlang/erlang-czmq cd zeromq.org && mkdir -p $example_dir [ -s $example_dir/index.md ] || cat >$example_dir/index.md
Example hello_world_server is missing for FsNetMQ . Would you like to contribute it? Then follow the steps below:
git clone https://github.com/zeromq/zeromq.org example_dir=content/docs/examples/fsharp/fsnetmq cd zeromq.org && mkdir -p $example_dir [ -s $example_dir/index.md ] || cat >$example_dir/index.md
Example hello_world_server is missing for fszmq . Would you like to contribute it? Then follow the steps below:
git clone https://github.com/zeromq/zeromq.org example_dir=content/docs/examples/fsharp/fszmq cd zeromq.org && mkdir -p $example_dir [ -s $example_dir/index.md ] || cat >$example_dir/index.md
package main import ( "log" "time" zmq "github.com/pebbe/zmq4" ) func main() zctx, _ := zmq.NewContext() s, _ := zctx.NewSocket(zmq.REP) s.Bind("tcp://*:5555") for // Wait for next request from client msg, _ := s.Recv(0) log.Printf("Received %s\n", msg) // Do some 'work' time.Sleep(time.Second * 1) // Send reply back to client s.Send("World", 0) > >
Example hello_world_server is missing for goczmq . Would you like to contribute it? Then follow the steps below:
git clone https://github.com/zeromq/zeromq.org example_dir=content/docs/examples/go/goczmq cd zeromq.org && mkdir -p $example_dir [ -s $example_dir/index.md ] || cat >$example_dir/index.md
Example hello_world_server is missing for zeromq4-haskell . Would you like to contribute it? Then follow the steps below:
git clone https://github.com/zeromq/zeromq.org example_dir=content/docs/examples/haskell/zeromq4-haskell cd zeromq.org && mkdir -p $example_dir [ -s $example_dir/index.md ] || cat >$example_dir/index.md
// Hello World server in Java // Binds REP socket to tcp://*:5555 // Expects "Hello" from client, replies with "World" import org.zeromq.SocketType; import org.zeromq.ZMQ; import org.zeromq.ZContext; public class hwserver public static void main(String[] args) throws Exception try (ZContext context = new ZContext()) // Socket to talk to clients ZMQ.Socket socket = context.createSocket(SocketType.REP); socket.bind("tcp://*:5555"); while (!Thread.currentThread().isInterrupted()) byte[] reply = socket.recv(0); System.out.println( "Received " + ": [" + new String(reply, ZMQ.CHARSET) + "]" ); String response = "world"; socket.send(response.getBytes(ZMQ.CHARSET), 0); Thread.sleep(1000); // Do some 'work' > > > >
Example hello_world_server is missing for JZMQ . Would you like to contribute it? Then follow the steps below:
git clone https://github.com/zeromq/zeromq.org example_dir=content/docs/examples/java/jzmq cd zeromq.org && mkdir -p $example_dir [ -s $example_dir/index.md ] || cat >$example_dir/index.md
Example hello_world_server is missing for jczmq . Would you like to contribute it? Then follow the steps below:
git clone https://github.com/zeromq/zeromq.org example_dir=content/docs/examples/java/jczmq cd zeromq.org && mkdir -p $example_dir [ -s $example_dir/index.md ] || cat >$example_dir/index.md
// Hello World server // Binds REP socket to tcp://*:5555 // Expects "Hello" from client, replies with "World" const zmq = require('zeromq'); async function runServer() const sock = new zmq.Reply(); await sock.bind('tcp://*:5555'); for await (const [msg] of sock) console.log('Received ' + ': [' + msg.toString() + ']'); await sock.send('World'); // Do some 'work' > > runServer();
Example hello_world_server is missing for perlzmq . Would you like to contribute it? Then follow the steps below:
git clone https://github.com/zeromq/zeromq.org example_dir=content/docs/examples/perl/perlzmq cd zeromq.org && mkdir -p $example_dir [ -s $example_dir/index.md ] || cat >$example_dir/index.md
# # Hello World server in Python # Binds REP socket to tcp://*:5555 # Expects b"Hello" from client, replies with b"World" # import time import zmq context = zmq.Context() socket = context.socket(zmq.REP) socket.bind("tcp://*:5555") while True: # Wait for next request from client message = socket.recv() print(f"Received request: message>") # Do some 'work' time.sleep(1) # Send reply back to client socket.send(b"World")
Example hello_world_server is missing for rbzmq . Would you like to contribute it? Then follow the steps below:
git clone https://github.com/zeromq/zeromq.org example_dir=content/docs/examples/ruby/rbzmq cd zeromq.org && mkdir -p $example_dir [ -s $example_dir/index.md ] || cat >$example_dir/index.md
#![crate_name = "helloworld_server"] //! Hello World server in Rust //! Binds REP socket to tcp://*:5555 //! Expects "Hello" from client, replies with "World" use std::thread; use std::time::Duration; fn main() let context = zmq::Context::new(); let responder = context.socket(zmq::REP).unwrap(); assert!(responder.bind("tcp://*:5555").is_ok()); let mut msg = zmq::Message::new(); loop responder.recv(&mut msg, 0).unwrap(); println!("Received <>", msg.as_str().unwrap()); thread::sleep(Duration::from_millis(1000)); responder.send("World", 0).unwrap(); > >
See the full example for more details.
const std = @import("std"); const zzmq = @import("zzmq"); pub fn main() !void std.log.info("Starting the server. ", .<>); var gpa = std.heap.GeneralPurposeAllocator(.<>)<>; defer if (gpa.deinit() == .leak) @panic("Memory leaked"); > const allocator = gpa.allocator(); var socket = try zzmq.ZSocket.init(allocator, zzmq.ZSocketType.Rep); defer socket.deinit(); _ = try socket.bind("tcp://127.0.0.1:5555"); while (true) // Wait for next request from client var frame = try socket.receive(); defer frame.deinit(); const data = try frame.data(); std.log.info("Received: ", .); > // Do some 'work' std.time.sleep(std.time.ns_per_s); // Send reply back to client var frame = try zzmq.ZFrame.init("World"); defer frame.deinit(); try socket.send(&frame, .<>); > > >
The server creates a socket of type response (you will read more about request-response later), binds it to port 5555 and then waits for messages. You can also see that we have zero configuration, we are just sending strings.
// Hello World client #include #include #include #include int main (void) printf ("Connecting to hello world server…\n"); void *context = zmq_ctx_new (); void *requester = zmq_socket (context, ZMQ_REQ); zmq_connect (requester, "tcp://localhost:5555"); int request_nbr; for (request_nbr = 0; request_nbr != 10; request_nbr++) char buffer [10]; printf ("Sending Hello %d…\n", request_nbr); zmq_send (requester, "Hello", 5, 0); zmq_recv (requester, buffer, 10, 0); printf ("Received World %d\n", request_nbr); > zmq_close (requester); zmq_ctx_destroy (context); return 0; >
// Hello World client #include int main (void) printf ("Connecting to hello world server…\n"); zsock_t *requester = zsock_new (ZMQ_REQ); zsock_connect (requester, "tcp://localhost:5555"); int request_nbr; for (request_nbr = 0; request_nbr != 10; request_nbr++) printf ("Sending Hello %d…\n", request_nbr); zstr_send (requester, "Hello"); char *str = zstr_recv (requester); printf ("Received World %d\n", request_nbr); zstr_free (&str); > zsock_destroy (&requester); return 0; >
// Hello World client #include #include #include using namespace std; int main(int argc, char *argv[]) const string endpoint = "tcp://localhost:5555"; // initialize the 0MQ context zmqpp::context context; // generate a push socket zmqpp::socket_type type = zmqpp::socket_type::req; zmqpp::socket socket (context, type); // open the connection cout <"Connecting to hello world server…" socket.connect(endpoint); int request_nbr; for (request_nbr = 0; request_nbr != 10; request_nbr++) // send a message cout <"Sending Hello " <"…" zmqpp::message message; // compose a message from a string and a number message <"Hello"; socket.send(message); string buffer; socket.receive(buffer); cout <"Received World " > >
#include #include #include int main() // initialize the zmq context with a single IO thread zmq::context_t context1>; // construct a REQ (request) socket and connect to interface zmq::socket_t socket::socket_type::req>; socket.connect("tcp://localhost:5555"); // set up some static data to send const std::string data"Hello">; for (auto request_num = 0; request_num 10; ++request_num) // send the request message std::cout "Sending Hello " ". " :: endl; socket.send(zmq::buffer(data), zmq::send_flags::none); // wait for reply from server zmq::message_t reply<>; socket.recv(reply, zmq::recv_flags::none); std::cout "Received " std::cout " (" ")" ; std::cout :: endl; > return 0; >
Example hello_world_client is missing for azmq . Would you like to contribute it? Then follow the steps below:
git clone https://github.com/zeromq/zeromq.org example_dir=content/docs/examples/cpp/azmq cd zeromq.org && mkdir -p $example_dir [ -s $example_dir/index.md ] || cat >$example_dir/index.md
Example hello_world_client is missing for czmqpp . Would you like to contribute it? Then follow the steps below:
git clone https://github.com/zeromq/zeromq.org example_dir=content/docs/examples/cpp/czmqpp cd zeromq.org && mkdir -p $example_dir [ -s $example_dir/index.md ] || cat >$example_dir/index.md
Example hello_world_client is missing for fbzmq . Would you like to contribute it? Then follow the steps below:
git clone https://github.com/zeromq/zeromq.org example_dir=content/docs/examples/cpp/fbzmq cd zeromq.org && mkdir -p $example_dir [ -s $example_dir/index.md ] || cat >$example_dir/index.md
using System; using NetMQ; using NetMQ.Sockets; static class Program public static void Main() Console.WriteLine("Connecting to hello world server…"); using(var requester = new RequestSocket()) requester.Connect("tcp://localhost:5555"); int requestNumber; for (requestNumber = 0; requestNumber != 10; requestNumber++) Console.WriteLine("Sending Hello . ", requestNumber); requester.SendFrame("Hello"); string str = requester.ReceiveFrameString(); Console.WriteLine("Received World ", requestNumber); > > > >
Example hello_world_client is missing for clrzmq4 . Would you like to contribute it? Then follow the steps below:
git clone https://github.com/zeromq/zeromq.org example_dir=content/docs/examples/csharp/clrzmq4 cd zeromq.org && mkdir -p $example_dir [ -s $example_dir/index.md ] || cat >$example_dir/index.md
Example hello_world_client is missing for dartzmq . Would you like to contribute it? Then follow the steps below:
git clone https://github.com/zeromq/zeromq.org example_dir=content/docs/examples/dart/dartzmq cd zeromq.org && mkdir -p $example_dir [ -s $example_dir/index.md ] || cat >$example_dir/index.md
-module(hello_world_client). -export([main/0]). main() -> application:start(chumak), Socket> = chumak:socket(req, "hello world client"), Pid> = chumak:connect(Socket, tcp, "localhost", 5555), send_messages(Socket, 10). send_messages(Socket, 0) -> ok; send_messages(Socket, N) -> io:format("Sending Hello ~p\n. ", [N]), ok = chumak:send(Socket, "Hello">>), RecvMessage> = chumak:recv(Socket), io:format("Received: ~p\n", [RecvMessage]), send_messages(Socket, N-1).
Example hello_world_client is missing for ezmq . Would you like to contribute it? Then follow the steps below:
git clone https://github.com/zeromq/zeromq.org example_dir=content/docs/examples/erlang/ezmq cd zeromq.org && mkdir -p $example_dir [ -s $example_dir/index.md ] || cat >$example_dir/index.md
Example hello_world_client is missing for erlang-czmq . Would you like to contribute it? Then follow the steps below:
git clone https://github.com/zeromq/zeromq.org example_dir=content/docs/examples/erlang/erlang-czmq cd zeromq.org && mkdir -p $example_dir [ -s $example_dir/index.md ] || cat >$example_dir/index.md
Example hello_world_client is missing for FsNetMQ . Would you like to contribute it? Then follow the steps below:
git clone https://github.com/zeromq/zeromq.org example_dir=content/docs/examples/fsharp/fsnetmq cd zeromq.org && mkdir -p $example_dir [ -s $example_dir/index.md ] || cat >$example_dir/index.md
Example hello_world_client is missing for fszmq . Would you like to contribute it? Then follow the steps below:
git clone https://github.com/zeromq/zeromq.org example_dir=content/docs/examples/fsharp/fszmq cd zeromq.org && mkdir -p $example_dir [ -s $example_dir/index.md ] || cat >$example_dir/index.md
package main import ( "fmt" zmq "github.com/pebbe/zmq4" ) func main() zctx, _ := zmq.NewContext() // Socket to talk to server fmt.Printf("Connecting to the server. \n") s, _ := zctx.NewSocket(zmq.REQ) s.Connect("tcp://localhost:5555") // Do 10 requests, waiting each time for a response for i := 0; i < 10; i++ fmt.Printf("Sending request %d. \n", i) s.Send("Hello", 0) msg, _ := s.Recv(0) fmt.Printf("Received reply %d [ %s ]\n", i, msg) > >
Example hello_world_client is missing for goczmq . Would you like to contribute it? Then follow the steps below:
git clone https://github.com/zeromq/zeromq.org example_dir=content/docs/examples/go/goczmq cd zeromq.org && mkdir -p $example_dir [ -s $example_dir/index.md ] || cat >$example_dir/index.md
Example hello_world_client is missing for zeromq4-haskell . Would you like to contribute it? Then follow the steps below:
git clone https://github.com/zeromq/zeromq.org example_dir=content/docs/examples/haskell/zeromq4-haskell cd zeromq.org && mkdir -p $example_dir [ -s $example_dir/index.md ] || cat >$example_dir/index.md
// Hello World client in Java // Connects REQ socket to tcp://localhost:5555 // Sends "Hello" to server, expects "World" back import org.zeromq.SocketType; import org.zeromq.ZMQ; import org.zeromq.ZContext; public class hwclient public static void main(String[] args) try (ZContext context = new ZContext()) System.out.println("Connecting to hello world server"); // Socket to talk to server ZMQ.Socket socket = context.createSocket(SocketType.REQ); socket.connect("tcp://localhost:5555"); for (int requestNbr = 0; requestNbr != 10; requestNbr++) String request = "Hello"; System.out.println("Sending Hello " + requestNbr); socket.send(request.getBytes(ZMQ.CHARSET), 0); byte[] reply = socket.recv(0); System.out.println( "Received " + new String(reply, ZMQ.CHARSET) + " " + requestNbr ); > > > >
Example hello_world_client is missing for JZMQ . Would you like to contribute it? Then follow the steps below:
git clone https://github.com/zeromq/zeromq.org example_dir=content/docs/examples/java/jzmq cd zeromq.org && mkdir -p $example_dir [ -s $example_dir/index.md ] || cat >$example_dir/index.md
Example hello_world_client is missing for jczmq . Would you like to contribute it? Then follow the steps below:
git clone https://github.com/zeromq/zeromq.org example_dir=content/docs/examples/java/jczmq cd zeromq.org && mkdir -p $example_dir [ -s $example_dir/index.md ] || cat >$example_dir/index.md
// Hello World client const zmq = require('zeromq'); async function runClient() console.log('Connecting to hello world server…'); // Socket to talk to server const sock = new zmq.Request(); sock.connect('tcp://localhost:5555'); for (let i = 0; i 10; i++) console.log('Sending Hello ', i); await sock.send('Hello'); const [result] = await sock.receive(); console.log('Received ', result.toString(), i); > > runClient();
Example hello_world_client is missing for perlzmq . Would you like to contribute it? Then follow the steps below:
git clone https://github.com/zeromq/zeromq.org example_dir=content/docs/examples/perl/perlzmq cd zeromq.org && mkdir -p $example_dir [ -s $example_dir/index.md ] || cat >$example_dir/index.md
# # Hello World client in Python # Connects REQ socket to tcp://localhost:5555 # Sends "Hello" to server, expects "World" back # import zmq context = zmq.Context() # Socket to talk to server print("Connecting to hello world server…") socket = context.socket(zmq.REQ) socket.connect("tcp://localhost:5555") # Do 10 requests, waiting each time for a response for request in range(10): print(f"Sending request request> …") socket.send(b"Hello") # Get the reply. message = socket.recv() print(f"Received reply request> [ message> ]")
Example hello_world_client is missing for rbzmq . Would you like to contribute it? Then follow the steps below:
git clone https://github.com/zeromq/zeromq.org example_dir=content/docs/examples/ruby/rbzmq cd zeromq.org && mkdir -p $example_dir [ -s $example_dir/index.md ] || cat >$example_dir/index.md
#![crate_name = "helloworld_client"] //! Hello World client fn main() println!("Connecting to hello world server. \n"); let context = zmq::Context::new(); let requester = context.socket(zmq::REQ).unwrap(); assert!(requester.connect("tcp://localhost:5555").is_ok()); let mut msg = zmq::Message::new(); for request_nbr in 0..10 println!("Sending Hello <>. ", request_nbr); requester.send("Hello", 0).unwrap(); requester.recv(&mut msg, 0).unwrap(); println!("Received World <>: <>", msg.as_str().unwrap(), request_nbr); > >
See the full example for more details.
const std = @import("std"); const zzmq = @import("zzmq"); pub fn main() !void std.log.info("Connecting to the server. ", .<>); var gpa = std.heap.GeneralPurposeAllocator(.<>)<>; defer if (gpa.deinit() == .leak) @panic("Memory leaked"); > const allocator = gpa.allocator(); var socket = try zzmq.ZSocket.init(allocator, zzmq.ZSocketType.Req); defer socket.deinit(); try socket.connect("tcp://127.0.0.1:5555"); // Do 10 requests, waiting each time for a response for (0..9) |i| // Send the request std.log.info("Sending request <>. ", .); var frame = try zzmq.ZFrame.init("Hello"); defer frame.deinit(); try socket.send(&frame, .<>); > // Receive the reply var frame = try socket.receive(); defer frame.deinit(); const data = try frame.data(); std.log.info("Received reply <> [ ]", .< i, data >); > > >
The client creates a socket of type request, connects and starts sending messages.
Both the send and receive methods are blocking (by default). For the receive it is simple: if there are no messages the method will block. For sending it is more complicated and depends on the socket type. For request sockets, if the high watermark is reached or no peer is connected the method will block.
© 2024 The ZeroMQ authors