Net.Zmq
0.4.1
dotnet add package Net.Zmq --version 0.4.1
NuGet\Install-Package Net.Zmq -Version 0.4.1
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="Net.Zmq" Version="0.4.1" />
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Net.Zmq" Version="0.4.1" />
<PackageReference Include="Net.Zmq" />
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add Net.Zmq --version 0.4.1
The NuGet Team does not provide support for this client. Please contact its maintainers for support.
#r "nuget: Net.Zmq, 0.4.1"
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package Net.Zmq@0.4.1
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=Net.Zmq&version=0.4.1
#tool nuget:?package=Net.Zmq&version=0.4.1
The NuGet Team does not provide support for this client. Please contact its maintainers for support.
Net.Zmq
A modern .NET 8+ binding for ZeroMQ (libzmq) with cppzmq-style API.
Features
- Modern .NET: Built for .NET 8.0+ with
[LibraryImport]source generators (no runtime marshalling overhead) - cppzmq Style: Familiar API for developers coming from C++
- Type Safe: Strongly-typed socket options, message properties, and enums
- Cross-Platform: Supports Windows, Linux, and macOS (x64, ARM64)
- Safe by Default: SafeHandle-based resource management
Installation
dotnet add package Net.Zmq
Quick Start
REQ-REP Pattern
using Net.Zmq;
// Server
using var ctx = new Context();
using var server = new Socket(ctx, SocketType.Rep);
server.Bind("tcp://*:5555");
var request = server.RecvString();
server.Send("World");
// Client
using var client = new Socket(ctx, SocketType.Req);
client.Connect("tcp://localhost:5555");
client.Send("Hello");
var reply = client.RecvString();
PUB-SUB Pattern
using Net.Zmq;
// Publisher
using var ctx = new Context();
using var pub = new Socket(ctx, SocketType.Pub);
pub.Bind("tcp://*:5556");
pub.Send("topic1 Hello subscribers!");
// Subscriber
using var sub = new Socket(ctx, SocketType.Sub);
sub.Connect("tcp://localhost:5556");
sub.Subscribe("topic1");
var message = sub.RecvString();
Router-to-Router Pattern
using System.Text;
using Net.Zmq;
using var ctx = new Context();
using var peerA = new Socket(ctx, SocketType.Router);
using var peerB = new Socket(ctx, SocketType.Router);
// Set explicit identities for Router-to-Router
peerA.SetOption(SocketOption.Routing_Id, "PEER_A"u8.ToArray());
peerB.SetOption(SocketOption.Routing_Id, "PEER_B"u8.ToArray());
peerA.Bind("tcp://127.0.0.1:5555");
peerB.Connect("tcp://127.0.0.1:5555");
// Peer B sends to Peer A (first frame = target identity)
peerB.Send("PEER_A"u8, SendFlags.SendMore);
peerB.Send("Hello from Peer B!");
// Peer A receives (first frame = sender identity)
Span<byte> idBuffer = stackalloc byte[64];
int idLen = peerA.Recv(idBuffer);
var senderId = idBuffer[..idLen];
var message = peerA.RecvString();
// Peer A replies using sender's identity
peerA.Send(senderId, SendFlags.SendMore);
peerA.Send("Hello back from Peer A!");
Polling
using Net.Zmq;
// Create Poller instance
using var poller = new Poller(capacity: 2);
// Add sockets and store their indices
int idx1 = poller.Add(socket1, PollEvents.In);
int idx2 = poller.Add(socket2, PollEvents.In);
// Poll for events
if (poller.Poll(timeout: 1000) > 0)
{
if (poller.IsReadable(idx1)) { /* handle socket1 */ }
if (poller.IsReadable(idx2)) { /* handle socket2 */ }
}
Message API
using Net.Zmq;
// Create and send message
using var msg = new Message("Hello World");
socket.Send(msg);
// Receive message
using var reply = new Message();
socket.Recv(reply);
Console.WriteLine(reply.ToString());
Socket Types
| Type | Description |
|---|---|
SocketType.Req |
Request socket (client) |
SocketType.Rep |
Reply socket (server) |
SocketType.Pub |
Publish socket |
SocketType.Sub |
Subscribe socket |
SocketType.Push |
Push socket (pipeline) |
SocketType.Pull |
Pull socket (pipeline) |
SocketType.Dealer |
Async request |
SocketType.Router |
Async reply |
SocketType.Pair |
Exclusive pair |
API Reference
Context
var ctx = new Context(); // Default
var ctx = new Context(ioThreads: 2, maxSockets: 1024); // Custom
ctx.SetOption(ContextOption.IoThreads, 4);
var threads = ctx.GetOption(ContextOption.IoThreads);
var (major, minor, patch) = Context.Version; // Get ZMQ version
bool hasCurve = Context.Has("curve"); // Check capability
Socket
var socket = new Socket(ctx, SocketType.Req);
// Connection
socket.Bind("tcp://*:5555");
socket.Connect("tcp://localhost:5555");
socket.Unbind("tcp://*:5555");
socket.Disconnect("tcp://localhost:5555");
// Send
socket.Send("Hello");
socket.Send(byteArray);
socket.Send(message, SendFlags.SendMore);
bool sent = socket.Send(data, SendFlags.DontWait); // false if would block
// Receive
string str = socket.RecvString();
int bytesRead = socket.Recv(buffer);
socket.Recv(message);
bool received = socket.TryRecvString(out string result);
bool gotData = socket.TryRecv(buffer, out int size);
// Options
socket.SetOption(SocketOption.Linger, 0);
int linger = socket.GetOption<int>(SocketOption.Linger);
Performance
Recommended Approach
Message Buffer Strategy: Use MessagePool
- Consistent performance across all message sizes
- GC-free (native memory pooling)
- Automatic return via ZeroMQ free callback (no manual management)
- Up to 3x faster than ByteArray at 128KB+ messages
- Avoids .NET Large Object Heap issues
Receive Mode:
- Single socket → Blocking
- Multiple sockets →
Poller
// Recommended: MessagePool for sending (automatic return)
var sendMsg = MessagePool.Shared.Rent(dataSize);
sourceData.CopyTo(sendMsg.Data);
socket.Send(sendMsg); // Automatically returned to pool
// Recommended: Blocking receive with Message
using var msg = new Message();
socket.Recv(msg);
// Process msg.Data
For fine-tuning options and detailed benchmarks, see docs/benchmarks.md.
Supported Platforms
| OS | Architecture |
|---|---|
| Windows | x64, ARM64 |
| Linux | x64, ARM64 |
| macOS | x64, ARM64 |
Documentation
Complete API documentation is available at: https://ulala-x.github.io/net-zmq/
The documentation includes:
- API Reference for all classes and methods
- Usage examples and patterns
- Performance benchmarks
- Platform-specific guides
Requirements
- .NET 8.0 or later
- Native libzmq library (automatically provided via Net.Zmq.Native package)
License
MIT License - see LICENSE for details.
Related Projects
- libzmq - ZeroMQ core library
- cppzmq - C++ binding (API inspiration)
- libzmq-native - Native binaries
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 was computed. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 was computed. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.
-
net8.0
- Microsoft.Extensions.ObjectPool (>= 8.0.0)
- Net.Zmq.Core (>= 0.4.1)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.