zmq Rust Bindings

repository·master·Indexed 21 days ago

https://github.com/erickt/rust-zmq

High-level Rust bindings for the libzmq library (version 0.10.0). The crate provides a safe API for ZeroMQ messaging patterns, including support for various socket types (REQ, REP, PUB, SUB, etc.), multipart messages, and CURVE security. It includes utilities for Z85 encoding/decoding, socket polling, and proxy functions to connect frontend and backend sockets.

Tokens
5.2K
Snippets
22
Records
26
Agent score
77%

What's inside zmq

  1. Use the zmq crate for ZeroMQ bindings

    master

    The zmq crate provides Rust bindings for the libzmq library. While the API is designed to be safe in the Rust sense, it follows the C API closely and may not feel idiomatic to Rust developers.

    To use it, you typically create a zmq::Context, then create sockets from that context, and finally perform operations like connect, send, or recv.

    fn main() {
        let ctx = zmq::Context::new();
    
        let socket = ctx.socket(zmq::REQ).unwrap();
        socket.connect("tcp://127.0.0.1:1234").unwrap();
        socket.send("hello world!", 0).unwrap();
    }
  2. Regenerate the C bindings for zmq-sys

    master

    The zmq-sys crate contains low-level, unsafe C bindings for ZeroMQ. While partially manual to handle platform-specific details, the bulk of the bindings are auto-generated from the zmq.h header file using bindgen. If you modify the header or need to refresh the bindings, use the bindgen command targeting the zmq.h file and redirect the output to zmq-sys/src/ffi.rs.

    bindgen \
       --with-derive-default \
       --whitelist-function "^zmq_.*" \
       --whitelist-type "^zmq_.*" \
       --whitelist-var "^ZMQ_.*" ~/src/zeromq-4.1.6/include/zmq.h \
       > zmq-sys/src/ffi.rs
  3. Explore ZeroMQ patterns via Rust implementations of the ZGuide

    master
    The examples/zguide directory contains Rust implementations of the original C examples from the ZeroMQ Guide (http://zguide.zeromq.org/). These examples are designed to help users understand ZeroMQ semantics and patterns while demonstrating how to use idiomatic Rust abstractions provided by the rust-zmq bindings. Use these examples to learn how to translate ZeroMQ concepts from C to Rust and to see how the bindings highlight higher-level abstractions.
  4. What is a Message and when should I use it?

    master

    A Message represents a single frame in ZeroMQ. Multipart messages are transmitted as a sequence of multiple Message objects.

    While rust-zmq provides convenience APIs (like Socket::recv_bytes() or Socket::send()) that handle message creation automatically, you should use the Message type explicitly when performing multiple operations in a loop. This allows you to reuse allocated memory and improve performance by avoiding repeated allocations.

  5. ZeroMQ Error Handling

    master

    The library uses a custom Result<T> type which is an alias for std::result::Result<T, Error>.

    Error is an enum representing ZeroMQ error codes (e.g., EAGAIN, EINTR, EADDRINUSE). It implements std::error::Error and std::fmt::Display. You can retrieve a human-readable error message using the .message() method on an Error instance.

  6. Basic socket usage example

    master

    This example demonstrates how to initialize a ZeroMQ context, create a REQ (Request) socket, connect to a TCP endpoint, and send a message.

    fn main() {
        let ctx = zmq::Context::new();
    
        let socket = ctx.socket(zmq::REQ).unwrap();
        socket.connect("tcp://127.0.0.1:1234").unwrap();
        socket.send("hello world!", 0).unwrap();
    }
  7. Send messages via Socket

    master

    You can send data using the send method. The send method is generic and works with any type that implements Sendable or Into<Message>. This includes &[u8], Vec<u8>, and &str.

    To send multipart messages, use send_multipart which takes an iterator of items that can be converted into messages.

    Common flags:

    • zmq::DONTWAIT: Non-blocking mode.
    • zmq::SNDMORE: Indicates that more frames of a multipart message will follow.
    // Sending a simple string
    socket.send("Hello World", 0).unwrap();
    
    // Sending multipart messages
    socket.send_multipart(vec!["Part 1", "Part 2"], 0).unwrap();
    
    // Sending with SNDMORE flag manually
    socket.send("Part 1", zmq::SNDMORE).unwrap();
    socket.send("Part 2", 0).unwrap();
  8. Create a Message from various data types

    master

    You can construct a Message using several methods depending on whether you want to copy data or transfer ownership:

    • Copying data: Use Message::from(data) where data is a &[u8], &str, or &String. This copies the content into the message.
    • Zero-copy (Ownership transfer): Use Message::from(data) where data is a Vec<u8> or Box<[u8]>. This transfers ownership of the buffer to the ZeroMQ message without copying.
    • Empty message: Use Message::new() to create an empty message frame.
    // Copying a slice
    let msg = Message::from(b"hello world");
    
    // Copying a string
    let msg = Message::from("hello world");
    
    // Zero-copy from Vec
    let vec = vec![1, 2, 3];
    let msg = Message::from(vec);
    
    // Zero-copy from Box
    let boxed = Box::new([1, 2, 3]);
    let msg = Message::from(boxed);
    
    // Empty message
    let msg = Message::new();
  9. Initialize a ZeroMQ Context

    master

    A Context is the container for all ZeroMQ sockets and manages the underlying I/O threads. It is thread-safe, can be cloned, and uses reference counting via Arc. When a Context is dropped, it automatically terminates the underlying C context.

    Note: Sockets created from a context hold a reference to it to prevent deadlocks during destruction. Explicitly calling Context::destroy() will attempt to terminate the context immediately.

    use zmq;
    
    let ctx = zmq::Context::new();
    // Or using Default
    let ctx = zmq::Context::default();
  10. Configure socket behavior using set()

    master

    To modify ZeroMQ socket options, use the set function. This function accepts a raw socket pointer (*mut c_void), an option identifier (c_int), and a value that implements the Setter trait. Supported types for the value include:

    • Numeric types: i32, i64, u64
    • Boolean: bool (mapped to 1 or 0 internally)
    • Strings: &str or Option<&str> (passing None sets the option to null)
    • Byte slices: &[u8]

    Note: The opt parameter refers to the ZeroMQ socket option constant (e.g., ZMQ_TCP_KEEPALIVE).

    // Example: Setting a boolean option
    set(sock_ptr, ZMQ_TCP_KEEPALIVE, true)?;
    
    // Example: Setting a string option
    set(sock_ptr, ZMQ_IDENTITY, "my_identity")?;
    
    // Example: Setting an option to null using Option
    set(sock_ptr, ZMQ_IDENTITY, None)?;
  11. Preallocate a Message with a specific size

    master

    If you need to preallocate a buffer of a specific size, use Message::with_size(len). This creates a message with len bytes initialized to 0.

    Warning: Avoid using the deprecated with_capacity_unallocated as it contains uninitialized memory and is highly unsafe.

    // Create a message pre-filled with 1024 zeroed bytes
    let mut msg = Message::with_size(1024);
    
    // You can now write to it like a slice
    msg[0] = 42;
  12. Retrieve socket options using get()

    master

    To read ZeroMQ socket options, use the get function. It requires a raw socket pointer (*mut c_void), an option identifier (c_int), and a type T that implements the Getter trait. The function returns Result<T>.

    Supported types for retrieval include:

    • i32, u32, i64, u64
    • bool (returns true if the underlying integer is 1)
    • PollEvents (for bitmask-based poll options)

    For complex or variable-length data, use the specialized functions get_bytes or get_string.

    // Example: Getting a boolean option
    let keepalive = get::<bool>(sock_ptr, ZMQ_TCP_KEEPALIVE)?;
    
    // Example: Getting an integer option
    let linger = get::<i32>(sock_ptr, ZMQ_LINGER)?;