NetMQ Documentation

repository·master·Indexed 25 days ago

https://github.com/zeromq/netmq

A 100% native C# port of the ZeroMQ messaging library providing high-performance, asynchronous messaging patterns, multiple transport protocols, and message filtering. It includes support for the Actor model via IShimHandler, async/await patterns using NetMQRuntime (from version 4.0.0.239-pre), and peer-to-peer discovery via NetMQBeacon. The library maintains two versions: Version 3 (stable) and Version 4 (current).

Tokens
17.6K
Snippets
31
Records
59
Agent score
84%

What's inside NetMQ

  1. Understand the NetMQ Actor Model concept

    master

    The NetMQ Actor Model is a mathematical model of concurrent computation that treats "actors" as the universal primitives. Instead of using shared data structures and synchronization primitives like lock(...) to manage multi-threaded access, the Actor model uses asynchronous message passing.

    Key characteristics of the Actor model:

    • Decoupling: Senders are decoupled from receivers via asynchronous communication.
    • Isolation: Actors communicate only through direct message passing. This avoids the need for locks and prevents timing issues associated with shared state.
    • Concurrency: Actors can concurrently send messages, create new actors, and determine their own behavior for the next message.
    • Address-based: Actors are identified by a "mailing address"; an actor can only communicate with actors whose addresses it knows.

    By using message passing, an actor works on its own copy of data, ensuring thread safety without the artificial delays caused by waiting for locks in traditional multi-threaded programming.

  2. Implement the Pub/Sub pattern with PublisherSocket and SubscriberSocket

    master

    NetMQ supports the Publish-Subscribe pattern using two specific socket types:

    • PublisherSocket: Used by senders to broadcast messages to unspecified receivers.
    • SubscriberSocket: Used by receivers to express interest in specific message classes (topics).

    Messages are conveyed using multipart messages where the first frame contains the topic information.

  3. Use NetMQTimer for periodic actions

    master

    A NetMQTimer allows you to perform actions periodically. To use it, specify an Interval (as a TimeSpan) and subscribe to the Elapsed event.

    Important: The Elapsed event is raised on the thread of the NetMQPoller that is running the timer. To ensure the timer actually fires, you must add the timer instance to a NetMQPoller and call poller.Run().

    var timer = new NetMQTimer(TimeSpan.FromMilliseconds(100));
    timer.Elapsed += (sender, args) => { /* handle timer event */ };
    using (var poller = new NetMQPoller { timer })
    {
        poller.Run();
    }
  4. Implement the Request/Response pattern

    master

    The Request/Response pattern uses RequestSocket and ResponseSocket to mimic a web-style request-response cycle. This pattern is synchronous and blocking.

    Standard Workflow:

    1. RequestSocket sends a request message.
    2. ResponseSocket receives the request.
    3. ResponseSocket sends a response message.
    4. RequestSocket receives the response.

    Warning: By default, these sockets are strict. Attempting to send twice without receiving, or receiving twice without sending, will throw an exception.

    using (var responseSocket = new ResponseSocket("@tcp://*:5555"))
    using (var requestSocket = new RequestSocket(">tcp://localhost:5555"))
    {
        Console.WriteLine("requestSocket : Sending 'Hello'");
        requestSocket.SendFrame("Hello");
        var message = responseSocket.ReceiveFrameString();
        Console.WriteLine("responseSocket : Server Received '{0}'", message);
        Console.WriteLine("responseSocket Sending 'World'");
        responseSocket.SendFrame("World");
        message = requestSocket.ReceiveFrameString();
        Console.WriteLine("requestSocket : Received '{0}'", message);
        Console.ReadLine();
    }
  5. Install NetMQ via NuGet

    master
    NetMQ can be installed as a NuGet package. This is a 100% native C# port of the ZeroMQ messaging library, providing asynchronous message queues, multiple messaging patterns, and various transport protocols.
  6. Optimize NetMQPoller performance for high throughput

    master

    Polling can be a bottleneck when handling thousands of messages per second. To improve performance, use Try* methods (like TryReceiveFrameString) inside the ReceiveReady event handler to drain all available messages in a single batch before returning control to the poller.

    To prevent a single busy socket from starving others, limit the number of messages fetched in each batch using a loop with a maximum count.

    // receiving 1000 messages or less if not available
    for (int count = 0; count < 1000; i++)
    {
        // exit the for loop if failed to receive a message
        if (!a.Socket.TryReceiveFrameString(out msg))
            break;
            
        // send a response
        a.Socket.Send("Response");
    }
  7. Use NetMQBeacon for peer-to-peer discovery

    master

    Use NetMQBeacon to implement a peer-to-peer discovery service on local networks. It allows nodes to broadcast and/or capture service announcements using IPv4 UDP broadcasts. This enables automatic discovery and connection to other NetMQ/CZMQ services without central configuration.

    Key Features:

    • Asynchronous Operation: Beacons are sent and received in the background.
    • Customizable Formats: You can define the format of outgoing beacons and set filters to validate incoming beacons.
    • Network Compatibility: It is a port of zbeacon from czmq and maintains network compatibility.

    Important Limitations:

    • Infrastructure Support: Your network infrastructure must support UDP broadcast. Most cloud providers do not support broadcast.
  8. Use Bind vs Connect

    master

    In NetMQ, Bind and Connect determine how queues are managed and how peers interact:

    • Bind: Use this on the most stable points in your architecture (e.g., a service provider). It allows peers to connect to it. Queues are created individually as each peer connects.
    • Connect: Use this for dynamic components with volatile endpoints (e.g., clients). It allows the socket to know at least one peer exists, enabling it to create a queue immediately.

    Warning: When using a ROUTER socket, queues are only created after the connected peer acknowledges the connection.

  9. Use NetMQQueue<T> for producer-consumer patterns

    master

    NetMQQueue<T> is a producer-consumer queue designed for scenarios with multiple producers and a single consumer. It is useful for eliminating boilerplate code related to marshalling operations onto a single thread.

    To use it effectively:

    1. Instantiate a NetMQQueue<T>.
    2. Add the queue instance to a NetMQPoller.
    3. Subscribe to the queue's ReceiveReady event to handle consumption.
    4. Call Enqueue(T) from various producer threads to add items to the queue.
    5. Use Dequeue() within the ReceiveReady event handler to retrieve and process items.
    using (var queue = new NetMQQueue<ICommand>())
    using (var poller = new NetMQPoller { queue })
    {
        queue.ReceiveReady += (sender, args) => ProcessCommand(queue.Dequeue());
        poller.RunAsync();
        // Then, from various threads...
        queue.Enqueue(new DoSomethingCommand());
        queue.Enqueue(new DoSomethingElseCommand());
    }
  10. Use TCP transport for network communication

    master

    TCP (tcp://) is the most common protocol in NetMQ. It is used for communicating between different hosts or processes over a network.

    Address Format: tcp://<host>:<port>

    • <host>: An IP address, hostname, or the wildcard * to match any host.
    • <port>: The port number.

    Example of a Request/Response pattern using TCP:

    using (var server = new ResponseSocket())
    using (var client = new RequestSocket())
    {
        server.Bind("tcp://*:5555");
        client.Connect("tcp://localhost:5555");
        Console.WriteLine("Sending Hello");
        client.SendFrame("Hello");
        var message = server.ReceiveFrameString();
        Console.WriteLine("Received {0}", message);
        Console.WriteLine("Sending World");
        server.SendFrame("World");
        message = client.ReceiveFrameString();
        Console.WriteLine("Received {0}", message);
    }