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.
- Project Overview
- Game Server Template
- Key Features
- Tech Stack
- Performance Benchmarks
- Reports
- Architecture
- Project Structure
- Core Implementation
- Getting Started
- License
FastPortSharp is a two-layer offering:
- Engine (
LibCommons+LibNetworks) โ protocol-neutral TCP listener / session / connector primitives validated under 10K concurrent sessions. Built onSocketAsyncEventArgsIOCP,Channel<T>, ArrayPool-backed circular buffers, and the .NET 10 lightweightLock. - 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.protofiles and handlers and you have a game server.
- 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.
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.
| 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.
# 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.
-
Add a new packet โ drop a
.protointoFastPortGameServerTemplate/Protocols/. Grpc.Tools regenerates C# classes ondotnet build. Add the new packet id toHandlers/PacketIds.cs(useโฅ 2000for user-defined ids). -
Implement a handler:
public sealed class MyHandler : IPacketHandler { public int PacketId => PacketIds.MyRequest; public void Handle(GameSession session, BasePacket packet) { /* ... */ } }
-
Register it in
Program.cs:builder.Services.AddSingleton<IPacketHandler, MyHandler>();
-
Replace the telemetry hook with your own
IGameServerTelemetryimplementation (e.g. backed by OpenTelemetry) by overriding the DI registration inProgram.cs. -
Tune buffer sizes in
Sessions/GameSessionFactory.cs(BufferCapacityBytes, default8 KiBโ same as the validated 10K-session benchmark configuration).
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.
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-lobbyThis 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.
| 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) |
| 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 |
Environment: Windows 11, Intel Core i5-14600K 3.50GHz, .NET 10
| 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 |
๐ View Full Benchmark Results
๐ View 10K Load Validation Results
dotnet run -c Release --project tests-projects/FastPortTestLoadRunner -- --sessions 10000 --payload random:4096-16384 --duration 5m --ramp-up 60s| 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 |
| 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รโ |
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
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()
Engine validation projects (
FastPortServer,FastPortClient,FastPortTestSmokeServer,FastPortTestLoadRunner,FastPortTestLoadValidation,FastPortTests) consume the same engine primitives but live separately from the template โ see Project Structure below.
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
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
}
}
}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);
}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);
}// 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!" });[ 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.
- .NET 10 SDK
- Visual Studio 2022 / Rider / VS Code
# 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 ReleaseThen customise FastPortGameServerTemplate/ per the
Customising the server section above.
# 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 Releasedotnet test FastPortSharp.sln -c Release --no-build
# 139 / 139 passed (as of 2026-05)This project is licensed under the MIT License.
boinred
๐ก This project is continuously improving. Feedback and contributions are welcome!