Dignus.Sockets 2.0.4

dotnet add package Dignus.Sockets --version 2.0.4
                    
NuGet\Install-Package Dignus.Sockets -Version 2.0.4
                    
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="Dignus.Sockets" Version="2.0.4" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Dignus.Sockets" Version="2.0.4" />
                    
Directory.Packages.props
<PackageReference Include="Dignus.Sockets" />
                    
Project file
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 Dignus.Sockets --version 2.0.4
                    
#r "nuget: Dignus.Sockets, 2.0.4"
                    
#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 Dignus.Sockets@2.0.4
                    
#: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=Dignus.Sockets&version=2.0.4
                    
Install as a Cake Addin
#tool nuget:?package=Dignus.Sockets&version=2.0.4
                    
Install as a Cake Tool

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:

  1. Packet format
  2. Packet definition
  3. Dispatch layer
  4. Direct mapper or pipeline
  5. Protocol handler
  6. Packet processor
  7. Session setup
  8. Server start

1. Packet Format

This example uses:

[length:int][protocol:int][body:byte[]]

Fields

  • length
    size of [protocol + body]

  • protocol
    message identifier

  • body
    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

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

await ProtocolPipelineInvoker<MyContext>.ExecuteAsync(ref context);
Legacy
await ProtocolPipelineInvoker<MyContext, MyHandler, string>.ExecuteAsync(ref context);

Pipeline Steps

  • Bind<TProtocol>()
    selects the protocol type and binder

  • Use()
    registers middleware such as logging, validation, or filtering

  • Build()
    finalizes the pipeline configuration

  • ExecuteAsync()
    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.
  • ISessionComponent allows 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 processor

  • second argument
    send-side serializer

  • third 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

  1. receive bytes
  2. split one packet
  3. parse protocol and body
  4. dispatch to the mapped handler
  5. serialize the response
  6. 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 body

  • Packet Processor
    handles framing and parsing

  • Mapper
    dispatches protocols directly

  • Pipeline
    composes protocol execution with middleware

  • Handler
    contains business logic

  • Session
    sends and receives data


Product 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. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.
  • .NETFramework 4.8

  • .NETFramework 4.8.1

  • .NETStandard 2.1

  • net10.0

  • net8.0

  • net9.0

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
Loading failed