Dignus.Sockets
2.0.4
dotnet add package Dignus.Sockets --version 2.0.4
NuGet\Install-Package Dignus.Sockets -Version 2.0.4
<PackageReference Include="Dignus.Sockets" Version="2.0.4" />
<PackageVersion Include="Dignus.Sockets" Version="2.0.4" />
<PackageReference Include="Dignus.Sockets" />
paket add Dignus.Sockets --version 2.0.4
#r "nuget: Dignus.Sockets, 2.0.4"
#:package Dignus.Sockets@2.0.4
#addin nuget:?package=Dignus.Sockets&version=2.0.4
#tool nuget:?package=Dignus.Sockets&version=2.0.4
Dignus.Sockets
Dignus.Sockets is a high-performance C# TCP/TLS/UDP server framework.
It provides async socket processing, custom packet serialization, protocol-based dispatch, and middleware-capable pipelines.
Benchmark: https://github.com/EomTaeWook/ServerPerformanceBenchmark
Features
- Async TCP/TLS/UDP networking
- Custom packet framing and serialization
- Protocol-based handler dispatch
- Direct mapper-based execution
- Binder-based pipeline system
- Middleware composition support
- Session component model
Quick Start
A server built with Dignus.Sockets typically consists of:
- Packet format
- Packet definition
- Dispatch layer
- Direct mapper or pipeline
- Protocol handler
- Packet processor
- Session setup
- Server start
1. Packet Format
This example uses:
[length:int][protocol:int][body:byte[]]
Fields
length
size of[protocol + body]protocol
message identifierbody
payload (JSON in this example)
Example
[12][1001]["hello"]
Notes
- This format is only an example.
- Protocol type can be changed.
- Body format can be changed.
- Length-based framing must be preserved.
2. Packet
using Dignus.Sockets.Interfaces;
using System.Text;
internal class Packet : IPacket
{
public int Protocol { get; }
public byte[] Body { get; }
public Packet(int protocol, byte[] body)
{
Protocol = protocol;
Body = body;
}
public Packet(int protocol, string value)
{
Protocol = protocol;
Body = Encoding.UTF8.GetBytes(value);
}
public int GetLength()
{
return Body.Length + sizeof(int);
}
}
3. Dispatch Layer
The dispatch layer maps protocol values to handler methods.
Binding
ProtocolHandlerMapper<EchoHandler, string>.BindProtocol<CSProtocol>();
This step:
- scans handler methods
- reads mapping attributes
- builds protocol-to-method bindings
Invocation
await ProtocolHandlerMapper<EchoHandler, string>.InvokeHandlerAsync(
handler,
protocol,
body);
This step:
- finds the mapped handler method
- executes it asynchronously
Available Mapper APIs
await ProtocolHandlerMapper<MyHandler, string>.InvokeHandlerAsync(handler, protocol, body);
await ProtocolSessionHandlerMapper<MyHandler, string>.InvokeHandlerAsync(handler, protocol, session, body);
4. Direct Mapper Usage
If you do not need a binder or middleware pipeline, you can bind handlers directly with a mapper.
ProtocolHandlerMapper<MyHandler, string>.BindProtocol<MyProtocol>();
await ProtocolHandlerMapper<MyHandler, string>.InvokeHandlerAsync(handler, protocol, body);
When to use
- simple servers
- rapid testing
- no middleware
- direct control over binding and invocation
5. Pipeline
Dignus.Sockets provides a binder-based pipeline system for protocol execution.
It supports:
- automatic protocol binding
- middleware composition
- async execution pipeline
Pipeline Builder (Recommended)
Use the binder-based builder for automatic protocol registration and middleware composition.
var binder = new ProtocolHandlerBinder<MiddlewareContext, CGProtocolHandler, string>();
// var binder = new ProtocolHandlerBinder<MiddlewareContext, CGProtocolHandler, string, ISession>();
ProtocolPipelineInvoker<MiddlewareContext>
.Bind<CGProtocolHandler, string, MyProtocol>(binder)
.Use((method, pipeline) =>
{
pipeline.Use((ref MiddlewareContext context, ref AsyncPipelineNext<MiddlewareContext> next) =>
{
Console.WriteLine($"Protocol {context.Protocol} invoked");
return next.InvokeAsync(ref context);
});
})
.Build();
Pipeline Execution
Recommended
await ProtocolPipelineInvoker<MyContext>.ExecuteAsync(ref context);
Legacy
await ProtocolPipelineInvoker<MyContext, MyHandler, string>.ExecuteAsync(ref context);
Pipeline Steps
Bind<TProtocol>()
selects the protocol type and binderUse()
registers middleware such as logging, validation, or filteringBuild()
finalizes the pipeline configurationExecuteAsync()
runs the pipeline for the given context
When to use
- middleware is required
- logging, validation, or filtering should be centralized
- protocol execution needs pre/post processing
- handler invocation should be composed declaratively
Notes
ProtocolPipelineInvoker<MyContext>is the recommended API for new code.ProtocolPipelineInvoker<MyContext, MyHandler, string>is the legacy form.- Both execute the configured async pipeline.
6. Handler
using Dignus.Sockets.Attributes;
using Dignus.Sockets.Interfaces;
using System.Text.Json;
internal class EchoHandler : IProtocolHandler<string>, ISessionComponent
{
private ISession _session;
public T DeserializeBody<T>(string body)
{
return JsonSerializer.Deserialize<T>(body);
}
[ProtocolName("EchoMessage")]
public void Process(EchoMessage echo)
{
var body = JsonSerializer.Serialize(echo);
_session.SendAsync(new Packet((int)SCProtocol.EchoMessageResponse, body));
}
public void OtherMessage(OtherMessage otherMessage)
{
var body = JsonSerializer.Serialize(otherMessage);
_session.SendAsync(new Packet((int)SCProtocol.OtherMessageResponse, body));
}
public void SetSession(ISession session)
{
_session = session;
}
public void Dispose()
{
_session = null;
}
}
Key Points
BindProtocol()reads handler metadata during initialization.- Protocol values are automatically mapped to handler methods.
InvokeHandlerAsync()executes the mapped method.ISessionComponentallows the handler to receive the current session.
7. Packet Processor
using Dignus.Collections;
using Dignus.Sockets.Interfaces;
using Dignus.Sockets.Processing;
using System.Text;
internal class PacketProcessor(EchoHandler echoHandler)
: SessionlessPacketProcessor, IPacketSerializer
{
private const int HeaderSize = sizeof(int) * 2;
private const int SizeToInt = sizeof(int);
public override async Task ProcessPacketAsync(ArraySegment<byte> packet)
{
var protocol = BitConverter.ToInt32(packet.Array, packet.Offset);
var size = packet.Count - SizeToInt;
var bodyString = Encoding.UTF8.GetString(packet.Array, packet.Offset + SizeToInt, size);
await ProtocolHandlerMapper<EchoHandler, string>.InvokeHandlerAsync(
echoHandler,
protocol,
bodyString);
}
public ArraySegment<byte> MakeSendBuffer(IPacket packet)
{
var sendPacket = (Packet)packet;
var packetSize = sendPacket.GetLength();
byte[] buffer = new byte[packetSize + SizeToInt];
Buffer.BlockCopy(BitConverter.GetBytes(packetSize), 0, buffer, 0, SizeToInt);
Buffer.BlockCopy(BitConverter.GetBytes(sendPacket.Protocol), 0, buffer, SizeToInt, SizeToInt);
Buffer.BlockCopy(sendPacket.Body, 0, buffer, HeaderSize, sendPacket.Body.Length);
return buffer;
}
public override bool TakeReceivedPacket(
ArrayQueue<byte> buffer,
out ArraySegment<byte> packet,
out int consumedBytes)
{
packet = null;
consumedBytes = 0;
if (buffer.Count < SizeToInt)
return false;
var length = BitConverter.ToInt32(buffer.Peek(SizeToInt));
if (buffer.Count < length + SizeToInt)
return false;
if (buffer.TryReadBytes(out _, SizeToInt) == false)
return false;
if (buffer.TrySlice(out packet, length) == false)
return false;
consumedBytes = length;
return true;
}
}
8. Session Setup
static SessionSetup PacketHandlerSetupFactory()
{
EchoHandler handler = new();
PacketProcessor processor = new(handler);
return new SessionSetup(
processor,
processor,
[handler]);
}
Structure
first argument
receive-side processorsecond argument
send-side serializerthird argument
session components
9. Server
using Dignus.Sockets;
using Dignus.Sockets.Tcp;
internal class EchoServer : TcpServerBase
{
public EchoServer(SessionConfiguration config) : base(config)
{
ProtocolHandlerMapper<EchoHandler, string>.BindProtocol<CSProtocol>();
}
}
10. Start
var config = new SessionConfiguration(PacketHandlerSetupFactory);
var server = new EchoServer(config);
server.Start(5000);
Runtime Flow
- receive bytes
- split one packet
- parse protocol and body
- dispatch to the mapped handler
- serialize the response
- send the response
Send vs SendAsync
Dignus.Sockets provides both synchronous and asynchronous send paths.
Both APIs use the same internal send path, so message ordering and send consistency are preserved in the same way.
The difference is how the send loop is executed.
Send executes the send loop directly on the current calling thread.
SendAsync schedules the send loop to the ThreadPool through Task.Run.
Because of this, SendAsync can introduce additional scheduling overhead, allocation, and GC pressure compared with Send.
Use Send when the send loop should run on the current calling thread.
Use SendAsync when the send loop should be scheduled to the ThreadPool.
Choosing an Execution Style
Direct Mapper
Use this when:
- the server is simple
- middleware is unnecessary
- direct binding is preferred
Pipeline
Use this when:
- middleware is needed
- cross-cutting concerns should be centralized
- protocol execution should be composed through a fluent builder
Summary
Packet
defines protocol and bodyPacket Processor
handles framing and parsingMapper
dispatches protocols directlyPipeline
composes protocol execution with middlewareHandler
contains business logicSession
sends and receives data
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net5.0 was computed. net5.0-windows was computed. net6.0 was computed. net6.0-android was computed. net6.0-ios was computed. net6.0-maccatalyst was computed. net6.0-macos was computed. net6.0-tvos was computed. net6.0-windows was computed. net7.0 was computed. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. 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 is compatible. 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 is compatible. 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. |
| .NET Core | netcoreapp3.0 was computed. netcoreapp3.1 was computed. |
| .NET Standard | netstandard2.1 is compatible. |
| .NET Framework | net48 is compatible. net481 is compatible. |
| MonoAndroid | monoandroid was computed. |
| MonoMac | monomac was computed. |
| MonoTouch | monotouch was computed. |
| Tizen | tizen60 was computed. |
| Xamarin.iOS | xamarinios was computed. |
| Xamarin.Mac | xamarinmac was computed. |
| Xamarin.TVOS | xamarintvos was computed. |
| Xamarin.WatchOS | xamarinwatchos was computed. |
NuGet packages (1)
Showing the top 1 NuGet packages that depend on Dignus.Sockets:
| Package | Downloads |
|---|---|
|
Dignus.ActorServer
Actor-based server framework built on top of Dignus and Dignus.Sockets for scalable message-driven network servers. |
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 2.0.4 | 0 | 6/8/2026 |
| 2.0.3 | 175 | 5/8/2026 |
| 2.0.2 | 218 | 4/29/2026 |
| 2.0.1 | 153 | 4/23/2026 |
| 2.0.0 | 182 | 4/16/2026 |
| 2.0.0-preview.5 | 59 | 4/11/2026 |
| 2.0.0-preview.4 | 66 | 4/9/2026 |
| 2.0.0-preview.3 | 80 | 3/30/2026 |
| 2.0.0-preview.2 | 68 | 3/23/2026 |
| 2.0.0-preview.1 | 57 | 3/22/2026 |
| 1.6.1 | 293 | 3/15/2026 |
| 1.6.0 | 119 | 3/14/2026 |
| 1.5.2 | 248 | 3/8/2026 |
| 1.5.1 | 119 | 3/2/2026 |
| 1.5.0 | 110 | 2/28/2026 |
| 1.4.2 | 111 | 2/24/2026 |
| 1.4.1 | 107 | 2/21/2026 |
| 1.4.0 | 107 | 2/21/2026 |
| 1.3.0 | 110 | 2/21/2026 |
| 1.2.2 | 117 | 2/15/2026 |