Skip to content

boinred/FastPortSharp

Folders and files

NameName
Last commit message
Last commit date

Latest commit

ย 

History

137 Commits
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 

Repository files navigation

๐Ÿš€ FastPortSharp

High-Performance .NET 10 TCP Engine + Game Server Starter Template

English | ํ•œ๊ตญ์–ด

FastPortSharp pairs a validated SocketAsyncEventArgs-based TCP engine (10K concurrent sessions tested) with a ready-to-bootstrap game server template. Use this repository as a GitHub Template Repository to spin up a new C# / .NET 10 game server in minutes โ€” focus on game logic, not on sockets, buffers, or framing.


๐Ÿ“‹ Table of Contents


๐ŸŽฏ Project Overview

FastPortSharp is a two-layer offering:

  • Engine (LibCommons + LibNetworks) โ€” protocol-neutral TCP listener / session / connector primitives validated under 10K concurrent sessions. Built on SocketAsyncEventArgs IOCP, Channel<T>, ArrayPool-backed circular buffers, and the .NET 10 lightweight Lock.
  • Game Server Template (FastPortGameServerTemplate + FastPortGameServerTemplate.SampleClient) โ€” a Generic Host based starter with Serilog, Protobuf, and a session / handler / dispatcher trio that consumes the engine. Drop in your .proto files and handlers and you have a game server.

Motivation

  • Reliable network processing in large-scale concurrent connection environments.
  • Modular, reusable engine components that can be embedded in any .NET host.
  • A "0 โ†’ 1 game server in minutes" path that stays opinionated only where it matters (host wiring, framing, telemetry hook) and out of the way everywhere else.

๐ŸŽฎ Game Server Template

FastPortGameServerTemplate/ is the starter project for building a new game server on top of the validated TCP engine (LibCommons + LibNetworks). It ships pre-wired with Generic Host, Serilog, Protobuf, and a session / handler / dispatcher trio so you can focus on game logic instead of plumbing.

What you get out of the box

Concern Implementation
Hosting Microsoft.Extensions.Hosting (Host.CreateApplicationBuilder)
Logging Serilog Console sink, configured from appsettings.json
Listener GameServer : LibNetworks.BaseMessageListener
Per-session GameSession : LibNetworks.Sessions.BaseSessionClient
Dispatch PacketDispatcher routes packet id โ†’ IPacketHandler
Sample protocol Sample.proto (Grpc.Tools, GrpcServices=None) โ€” EchoRequest (1001) / EchoResponse (1002)
Telemetry hook IGameServerTelemetry + NullGameServerTelemetry (replace via DI)
Sample client FastPortGameServerTemplate.SampleClient/ for verifying full echo round-trip
Config appsettings.json โ†’ GameServerOptions (listen address / port / max sessions)

The template references only LibCommons + LibNetworks โ€” never FastPortServer, FastPortClient, Protocols/, or any test project. This keeps the engine boundary clean and your game-server code free of test scaffolding.

Quickstart

# 1. Build the whole solution
dotnet build FastPortSharp.sln -c Release

# 2. Start the template server (terminal 1)
dotnet run --project template-projects/FastPortGameServerTemplate -c Release
# โ†’ "GameServer listening" on 0.0.0.0:7777

# 3. Verify a full Protobuf echo round-trip (terminal 2)
dotnet run --project template-projects/FastPortGameServerTemplate.SampleClient -c Release
# โ†’ "EchoResponse received. Message=\"Hello, FastPort!\", RTT=...ms"

Listen address / port / max sessions are configured in FastPortGameServerTemplate/appsettings.json.

Customising the server

  1. Add a new packet โ€” drop a .proto into FastPortGameServerTemplate/Protocols/. Grpc.Tools regenerates C# classes on dotnet build. Add the new packet id to Handlers/PacketIds.cs (use โ‰ฅ 2000 for user-defined ids).

  2. Implement a handler:

    public sealed class MyHandler : IPacketHandler
    {
        public int PacketId => PacketIds.MyRequest;
        public void Handle(GameSession session, BasePacket packet) { /* ... */ }
    }
  3. Register it in Program.cs:

    builder.Services.AddSingleton<IPacketHandler, MyHandler>();
  4. Replace the telemetry hook with your own IGameServerTelemetry implementation (e.g. backed by OpenTelemetry) by overriding the DI registration in Program.cs.

  5. Tune buffer sizes in Sessions/GameSessionFactory.cs (BufferCapacityBytes, default 8 KiB โ€” same as the validated 10K-session benchmark configuration).

Distribution

This repository is the GitHub Template Repository for the game server template. Click "Use this template" on GitHub, or git clone/fork, then prune the projects you don't need. Uploading the engine to nuget.org is intentionally out of scope โ€” consumers either clone the repo or reuse the engine via ProjectReference within the same solution.

Scaffold a fresh project (one command)

If you'd rather start from a clean self-contained checkout (just your server + the engine, with the template token renamed to your project name), use the cross-platform scaffold script:

# Linux / macOS
scripts/scaffold-game-server.sh   MyLobbyServer ../my-lobby

# Windows / cross-platform
pwsh -File scripts/scaffold-game-server.ps1 MyLobbyServer ../my-lobby

This copies FastPortGameServerTemplate/ + LibCommons/ + LibNetworks/ to the destination, renames everything from FastPortGameServerTemplate to your chosen name, generates <name>.sln, runs git init, and smoke-tests with dotnet build. See scripts/README.md for options (--force, --no-git, --dry-run, --skip-smoke) and exit codes.

For the full step-by-step walkthrough and Korean version, see FastPortGameServerTemplate/README.md and FastPortGameServerTemplate/QUICKSTART.ko.md.


โœจ Key Features

Feature Description
Async I/O High concurrency processing with SocketAsyncEventArgs-based IOCP pattern
Circular Buffer ArrayPool-backed circular buffer minimises GC pressure under sustained throughput
Channel<T> Bounded Channel<T> for receive/send pipelines โ€” 4ร— faster, 69% less memory than BufferBlock<T>
Protocol Buffers Efficient message serialization based on Google Protobuf, generated via Grpc.Tools
Session Management Flexible session creation and management based on the Factory pattern
Keep-Alive Connection state monitoring via TCP Keep-Alive settings
Generic Host Microsoft.Extensions.Hosting lifecycle for both server and client
Game Server Template Drop-in starter with Serilog, Protobuf, session / handler / dispatcher pre-wired
Latency Statistics Real-time RTT, server processing time, and network delay measurement (load runner)

๐Ÿ›  Tech Stack

Domain Technology
Language C# 14 / .NET 10
Async Pattern SocketAsyncEventArgs (IOCP)
Concurrency Channel<T>, .NET 10 Lock
Serialization Google Protocol Buffers + Grpc.Tools (gen, no gRPC runtime)
DI Container Microsoft.Extensions.DependencyInjection
Hosting Microsoft.Extensions.Hosting (Generic Host)
Logging Serilog (template) / Microsoft.Extensions.Logging
Testing MSTest, FastPortTestLoadRunner, FastPortTestLoadValidation

๐Ÿ“Š Performance Benchmarks

Environment: Windows 11, Intel Core i5-14600K 3.50GHz, .NET 10

Key Performance Indicators

Item Result Note
CircularBuffer Write 244~670 ns 64B~8KB data
CircularBuffer vs QueueBuffer 20ร— faster Based on 4KB data
Channel vs BufferBlock 4ร— faster 69% memory savings
.NET 10 Lock vs lock 9% faster Based on 10,000 iterations

๐Ÿ“ˆ Detailed Benchmark Results

๐Ÿ‘‰ View Full Benchmark Results

๐Ÿ‘‰ View 10K Load Validation Results

Running Load Tests

dotnet run -c Release --project tests-projects/FastPortTestLoadRunner -- --sessions 10000 --payload random:4096-16384 --duration 5m --ramp-up 60s

๐Ÿ“‘ Reports

Performance Test Reports

Report Description Link
Pre-optimization Performance Report Latency performance test results before optimization ๐Ÿ“„ View
Lock-optimized Performance Report Performance test after applying ArrayPool + .NET 10 Lock ๐Ÿ“„ View
Channel-optimized Performance Report Performance test after applying full optimizations ๐Ÿ“„ View
Historical Benchmark Results Component-specific micro benchmark results captured before the load runner migration ๐Ÿ“„ View
10K Load Validation Results Same-machine 10K load validation comparison for server send backpressure optimization ๐Ÿ“„ View

Optimization Summary

Metric Before Final (Channel applied) Improvement
Average RTT 96.03 ms 55.68 ms 42.0%โ†“
Server Processing Time 0.234 ms 0.002 ms 99.1%โ†“
Max RTT 434.40 ms 83.13 ms 80.9%โ†“
Throughput ~489/min ~1,080/min 2.2ร—โ†‘

๐Ÿ— Architecture

System Structure

flowchart TB
    subgraph Template ["๐ŸŽฎ FastPortGameServerTemplate"]
        GS[GameServer : BaseMessageListener]
        GHS[GameServerHostedService]
        GSE[GameSession : BaseSessionClient]
        PD[PacketDispatcher]
        PH[IPacketHandler / EchoHandler]
        TGT[IGameServerTelemetry]
        SP[Sample.proto]
    end

    subgraph SampleClient ["๐Ÿงช FastPortGameServerTemplate.SampleClient"]
        SC[SampleClientConnector : BaseMessageConnector]
        SCS[SampleClientSession : BaseSessionServer]
        ES[EchoSignal]
    end

    subgraph LibNetworks ["๐Ÿ“ฆ LibNetworks (engine)"]
        BL[BaseListener / BaseMessageListener]
        BC[BaseConnector / BaseMessageConnector]
        BS[BaseSession / BaseSessionClient / BaseSessionServer]
        SEP[SocketEventsPool]
    end

    subgraph LibCommons ["๐Ÿ“ฆ LibCommons (engine)"]
        CB[ArrayPoolCircularBuffers]
        BP[BasePacket]
        IDG[IDGenerator]
    end

    GS --> BL
    GHS --> GS
    GSE --> BS
    GSE --> PD
    PD --> PH
    PD --> TGT
    SP --> GSE

    SC --> BC
    SCS --> BS
    SC --> SCS
    SCS --> ES

    BS --> CB
    BS --> BP
    BL --> SEP
    BC --> SEP

    SCS -. EchoRequest 1001 / EchoResponse 1002 .-> GSE
Loading

Server Connection Flow (template)

sequenceDiagram
    participant C as SampleClient
    participant L as GameServer (Listener)
    participant SF as GameSessionFactory
    participant S as GameSession
    participant D as PacketDispatcher
    participant H as EchoHandler

    C->>L: TCP Connect (127.0.0.1:7777)
    L->>SF: Create(socket)
    SF->>S: new GameSession(...)
    S->>S: OnAccepted()
    C->>S: EchoRequest(1001, "Hello")
    S->>D: Dispatch(packet)
    D->>H: Handle(session, packet)
    H->>S: session.Send(EchoResponse, 1002)
    S->>C: EchoResponse(1002, "Hello", serverUnixMs)
    C->>S: Disconnect
    S->>S: OnDisconnected()
Loading

Engine validation projects (FastPortServer, FastPortClient, FastPortTestSmokeServer, FastPortTestLoadRunner, FastPortTestLoadValidation, FastPortTests) consume the same engine primitives but live separately from the template โ€” see Project Structure below.


๐Ÿ“ Project Structure

FastPortSharp/
โ”œโ”€โ”€ ๐Ÿ“‚ LibCommons/                            # Engine: buffers, packet, IDs
โ”‚   โ”œโ”€โ”€ BaseCircularBuffers.cs                 # Circular buffer (.NET 10 Lock)
โ”‚   โ”œโ”€โ”€ ArrayPoolCircularBuffers.cs            # ArrayPool-backed circular buffer
โ”‚   โ”œโ”€โ”€ BasePacket.cs                          # Packet structure
โ”‚   โ”œโ”€โ”€ IBuffers.cs                            # Buffer interface
โ”‚   โ”œโ”€โ”€ IDGenerator.cs                         # Session/request id generator
โ”‚   โ””โ”€โ”€ LatencyStats.cs                        # Latency stats (used by load runner)
โ”‚
โ”œโ”€โ”€ ๐Ÿ“‚ LibNetworks/                           # Engine: TCP listener / session / connector
โ”‚   โ”œโ”€โ”€ BaseListener.cs / BaseMessageListener.cs
โ”‚   โ”œโ”€โ”€ BaseConnector.cs / BaseMessageConnector.cs
โ”‚   โ”œโ”€โ”€ SocketEventsPool.cs
โ”‚   โ”œโ”€โ”€ Extensions/BasePacket+Extensions.cs    # ParseMessageFromPacket<T>
โ”‚   โ””โ”€โ”€ ๐Ÿ“‚ Sessions/
โ”‚       โ”œโ”€โ”€ BaseSession.cs                      # Channel<T> + ArrayPool framing
โ”‚       โ”œโ”€โ”€ BaseSessionClient.cs                # Server-side accepted session
โ”‚       โ”œโ”€โ”€ BaseSessionServer.cs                # Client-side outgoing session
โ”‚       โ””โ”€โ”€ IClientSessionFactory.cs
โ”‚
โ”œโ”€โ”€ ๐Ÿ“‚ template-projects/                      # Grouped game-server template surface
โ”‚   โ”œโ”€โ”€ ๐ŸŽฎ FastPortGameServerTemplate/          # Game server starter (template)
โ”‚   โ”‚   โ”œโ”€โ”€ Application/
โ”‚   โ”‚   โ”‚   โ”œโ”€โ”€ GameServer.cs                   # : BaseMessageListener
โ”‚   โ”‚   โ”‚   โ”œโ”€โ”€ GameServerHostedService.cs      # IHostedService lifecycle
โ”‚   โ”‚   โ”‚   โ””โ”€โ”€ PacketDispatcher.cs
โ”‚   โ”‚   โ”œโ”€โ”€ Sessions/
โ”‚   โ”‚   โ”‚   โ”œโ”€โ”€ GameSession.cs                  # : BaseSessionClient
โ”‚   โ”‚   โ”‚   โ””โ”€โ”€ GameSessionFactory.cs
โ”‚   โ”‚   โ”œโ”€โ”€ Handlers/
โ”‚   โ”‚   โ”‚   โ”œโ”€โ”€ IPacketHandler.cs
โ”‚   โ”‚   โ”‚   โ””โ”€โ”€ EchoHandler.cs                  # 1001 โ†’ 1002 round-trip sample
โ”‚   โ”‚   โ”œโ”€โ”€ Telemetry/
โ”‚   โ”‚   โ”‚   โ”œโ”€โ”€ IGameServerTelemetry.cs
โ”‚   โ”‚   โ”‚   โ””โ”€โ”€ NullGameServerTelemetry.cs
โ”‚   โ”‚   โ”œโ”€โ”€ Configuration/GameServerOptions.cs
โ”‚   โ”‚   โ”œโ”€โ”€ Program.cs                          # Generic Host + Serilog wiring
โ”‚   โ”‚   โ”œโ”€โ”€ appsettings.json
โ”‚   โ”‚   โ”œโ”€โ”€ README.md / QUICKSTART.ko.md
โ”‚   โ”‚   โ””โ”€โ”€ FastPortGameServerTemplate.csproj   # <Protobuf Include="..\Protos\*.proto"/>
โ”‚   โ”‚
โ”‚   โ”œโ”€โ”€ ๐Ÿ“ Protos/                              # Shared .proto files (no csproj)
โ”‚   โ”‚   โ”œโ”€โ”€ PacketIds.proto                     # enum PacketIds { 1001, 1002, ... }
โ”‚   โ”‚   โ””โ”€โ”€ Sample.proto                        # EchoRequest / EchoResponse messages
โ”‚   โ”‚
โ”‚   โ””โ”€โ”€ ๐Ÿงช FastPortGameServerTemplate.SampleClient/  # Verifies full echo round-trip
โ”‚       โ”œโ”€โ”€ Sessions/
โ”‚       โ”‚   โ”œโ”€โ”€ SampleClientSession.cs          # : BaseSessionServer
โ”‚       โ”‚   โ””โ”€โ”€ SampleClientSessionFactory.cs
โ”‚       โ”œโ”€โ”€ SampleClientConnector.cs            # : BaseMessageConnector
โ”‚       โ”œโ”€โ”€ SampleClientHostedService.cs        # Connects, sends 1001, awaits 1002
โ”‚       โ”œโ”€โ”€ SampleClientOptions.cs / EchoSignal.cs
โ”‚       โ”œโ”€โ”€ Program.cs / appsettings.json
โ”‚       โ””โ”€โ”€ FastPortGameServerTemplate.SampleClient.csproj
โ”‚
โ”œโ”€โ”€ ๐Ÿ“‚ FastPortServer/                        # Engine sample/host (validation)
โ”œโ”€โ”€ ๐Ÿ“‚ FastPortClient/                        # Engine sample/client (with LatencyStats)
โ”œโ”€โ”€ ๐Ÿ“‚ Protocols/                             # Engine-internal sample protocol
โ”œโ”€โ”€ ๐Ÿ“‚ tests-projects/                        # Grouped test surface
โ”‚   โ”œโ”€โ”€ FastPortTestSmokeServer/              # Smoke/echo test server
โ”‚   โ”œโ”€โ”€ FastPortTestLoadRunner/               # 10K-session load runner
โ”‚   โ”œโ”€โ”€ FastPortTestLoadValidation/           # Load validation harness
โ”‚   โ”œโ”€โ”€ FastPortTests/                        # MSTest unit tests (139 cases)
โ”‚   โ””โ”€โ”€ LibTestTelemetry/                     # Test-only telemetry contracts (JSONL)
โ”‚
โ”œโ”€โ”€ ๐Ÿ“‚ FastPortDashboard.Maui/                # MAUI desktop dashboard (macOS / Windows)
โ”‚                                              # Built via FastPortSharp.Dashboard.sln
โ”‚
โ”œโ”€โ”€ ๐Ÿ“‚ docs/                                  # Performance reports, PDCA archive
โ””โ”€โ”€ FastPortSharp.sln

๐Ÿ”ง Core Implementation

1. Circular Buffer

Efficiently handles continuous data streams without memory reallocation.

public class BaseCircularBuffers : IBuffers, IDisposable
{
    private byte[] m_Buffers;
    private int m_Head = 0;  // Read position
    private int m_Tail = 0;  // Write position

    // Uses .NET 10 lightweight Lock
    private readonly Lock m_Lock = new();

    public int Write(byte[] buffers, int offset, int count)
    {
        lock (m_Lock)
        {
            // Auto-expansion when capacity is low
            // Circular write logic for memory efficiency
        }
    }
}

2. Channel<T> Based Packet Processing

Uses Channel<T> for high-performance asynchronous message delivery.

// 4ร— faster and 69% memory savings compared to BufferBlock<T>
private readonly Channel<BasePacket> m_ReceivedPackets =
    Channel.CreateBounded<BasePacket>(new BoundedChannelOptions(1000)
    {
        FullMode = BoundedChannelFullMode.Wait,
        SingleReader = true,
        SingleWriter = true
    });

await foreach (var packet in m_ReceivedPackets.Reader.ReadAllAsync(cancellationToken))
{
    OnReceived(packet);
}

3. Factory Pattern Based Session Creation

public interface IClientSessionFactory
{
    BaseSessionClient Create(Socket socket);
}

// Template's GameSessionFactory wires session + dispatcher + telemetry.
public sealed class GameSessionFactory : IClientSessionFactory
{
    public BaseSessionClient Create(Socket clientSocket) => new GameSession(
        m_Logger, clientSocket,
        new ArrayPoolCircularBuffers(8 * 1024),
        new ArrayPoolCircularBuffers(8 * 1024),
        m_Dispatcher, m_Telemetry);
}

4. Protobuf Round-Trip in the Template

// Server (EchoHandler)
public void Handle(GameSession session, BasePacket packet)
{
    if (!packet.ParseMessageFromPacket<EchoRequest>(out _, out var request) || request is null) return;
    var response = new EchoResponse
    {
        Message = request.Message,
        ServerUnixMs = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(),
    };
    session.Send(PacketIds.EchoResponse, response);
}

// Client (SampleClientSession.OnConnected)
RequestSendMessage(PacketIds.EchoRequest, new EchoRequest { Message = "Hello, FastPort!" });

5. Wire Framing

[ 2-byte length header ][ int32 LE packet id ][ protobuf payload ... ]

LibNetworks.Sessions.BaseSession.RequestSendMessage<T> and LibNetworks.Extensions.BasePacketExtensions.ParseMessageFromPacket<T> encode and decode this framing โ€” handlers and the dispatcher only see BasePacket and the strongly-typed Protobuf message.


๐Ÿš€ Getting Started

Prerequisites

  • .NET 10 SDK
  • Visual Studio 2022 / Rider / VS Code

Path A โ€” Build a new game server (recommended)

# Clone or "Use this template" on GitHub
git clone https://github.com/boinred/FastPortSharp.git
cd FastPortSharp

# Build
dotnet build FastPortSharp.sln -c Release

# Run the template server
dotnet run --project template-projects/FastPortGameServerTemplate -c Release

# In another terminal, verify the full echo round-trip
dotnet run --project template-projects/FastPortGameServerTemplate.SampleClient -c Release

Then customise FastPortGameServerTemplate/ per the Customising the server section above.

Path B โ€” Study the engine internals or run benchmarks

# Engine sample server / client (no game logic, raw echo on legacy protocol)
dotnet run --project FastPortServer -c Release
dotnet run --project FastPortClient -c Release

# 10K-session load runner
dotnet run -c Release --project tests-projects/FastPortTestLoadRunner -- \
  --sessions 10000 --payload random:4096-16384 --duration 5m --ramp-up 60s

# Smoke server with structured telemetry
dotnet run --project tests-projects/FastPortTestSmokeServer -c Release

Run Tests

dotnet test FastPortSharp.sln -c Release --no-build
# 139 / 139 passed (as of 2026-05)

๐Ÿ“ License

This project is licensed under the MIT License.


๐Ÿ‘ค Developer

boinred

GitHub


๐Ÿ’ก This project is continuously improving. Feedback and contributions are welcome!

About

High-performance async TCP socket server/client framework for .NET 10 with IOCP, Channel<T>, ArrayPool, and Protocol Buffers. Optimized for game servers and real-time systems.

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Contributors