KcpCSharpR1 0.10.0

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

KcpCSharpR1

🌐 English | 한국어

A C# library that adds exactly as much reliability as you need on top of UDP. A KCP implementation for real-time games.

A C# port and rebuild that continues the lineage from skywind3000/kcp (C) through xtaci/kcp-go (Go). See Lineage below for details.

net8.0 netstandard2.1 license

📖 Online book (Korean): C#과 KCP로 배우는 실시간 게임 네트워킹


What Is KCP

TCP guarantees that every byte arrives in order. That's perfect for file transfer, but it becomes a problem in games. When one packet is lost, every newer packet that already arrived is held back too (head-of-line blocking). That's why a character freezes for 0.25 seconds and then teleports.

KCP puts reliability on top of UDP only where you need it.

Channel Guarantees Use for
Reliable (Send) delivery + ordering chat, inventory, hit results
Unreliable (SendUnreliable) none position snapshots, input

It also recovers more aggressively than TCP — 1.5× RTO backoff (TCP uses 2×), 30 ms minimum RTO (TCP is 200 ms+), fast retransmit plus early retransmit. A trade: spend a bit more bandwidth, buy back latency.

30-Second Quick Start

git clone https://github.com/jacking75/kcp-csharp
cd kcp-csharp
dotnet run --project samples/01-Echo/Server     # terminal 1
dotnet run --project samples/01-Echo/Client     # terminal 2

Server

using KcpCSharpR1.Transport;

using var server = new KcpServer(27001);

server.SessionConnected += s => Console.WriteLine($"connected {s.RemoteEndPoint}");
server.ReliableReceived += (s, data) => s.Send(data.Span);            // echo
server.SessionDisconnected += (s, why) => Console.WriteLine($"closed {why}");

server.Start();
Console.WriteLine("Listening on UDP 27001. Press Ctrl+C to stop.");

// Start() spins up a background thread and returns immediately.
// Without something blocking here, the program would just exit.
using var quit = new ManualResetEventSlim(false);
Console.CancelKeyPress += (_, e) => { e.Cancel = true; quit.Set(); };
quit.Wait();

server.Stop();

Full code: samples/01-Echo/Server/Program.cs.

Client

using var client = new KcpClient();
client.ReliableReceived += (_, data) => Console.WriteLine(Encoding.UTF8.GetString(data.Span));

var session = await client.ConnectAsync(new IPEndPoint(IPAddress.Loopback, 27001));
session.Send(Encoding.UTF8.GetBytes("Hello KCP"));

while (true)          // every frame, in your game loop
{
    client.Update();  // ★ nothing happens unless you call this
    await Task.Delay(10);
}

Features

Two channels: reliable / unreliable Choosing per message is the core of this library
Stateless cookie handshake HMAC-based. A SYN flood can't fill up server memory
Session lifecycle management keepalive (PING/PONG), timeouts, graceful FIN close, dead-link detection
AES-256-GCM encryption Authenticated encryption + a 64-bit replay window
Reed-Solomon FEC kcp-go compatible. −70% retransmits at 20% loss
Allocation-free design 0 B/op on the steady-state send/receive path (verified by benchmark)
Zero-copy receive ReliableReceivedSpan hands you the KCP segment directly, no copy
Thread-boundary APIs A send outbox for game threads + a receive event queue
Min-heap scheduler Only updates sessions that are actually due, even with 10,000 sessions
Observability Periodic snapshots of session count, retransmit rate, RTT p50/p95/p99
Zero external dependencies Both core and transport layer. MonoGame in the samples is the only exception
Wire-compatible with original kcp RawMode talks directly to a kcp-go server

Performance

Measured with client and server running together on the same PC. Reproduction commands are in docs/benchmarks.md.

Metric Value
1KB × 1,000 round trips 321 µs (441 µs before optimization, −27%)
Steady-state allocation 0 B/op
1,000 sessions · 60s 970,627 messages all round-tripped, 0 mismatches, 1.13% retransmit
300 sessions · 60s 0.00% retransmit, RTT p99 48.5ms, 0 Gen2 collections
Encryption cost 0.36 µs per packet (at 1,376B)

The 1,000-session numbers above were measured with client and server on the same PC. They are not a standalone server capacity figure.

How Many Clients Can It Handle

The receive loop is a single thread, so the ceiling is set by "what else you put on that thread."

Setup Recommended per process
Plain KCP + game logic on a separate thread (EnableEventQueue) 2,000–3,000
Plain KCP + game logic run inside the event handler 500–1,000
Add AES-GCM 10–15% less than the above
FEC on 300–500

Session lookup is O(1) and the timer is an O(log n) min-heap, so the data structures were designed with 10,000 sessions in mind. In practice, what you hit first is memory (MaxSendBacklog × 2KB) and game logic riding on the receive thread. Sizing methodology and the scale-out order are in Chapter 14 and Chapter 17 of the book (Korean only).

Samples

Five samples in increasing difficulty, plus one tool. Each sample has its own README.

Sample Difficulty What you learn
01-Echo ★1 The minimal cycle: connect, send/receive, close
02-Chat ★2 Designing an application protocol, server-side validation
03-Gomoku ★3 Authoritative server, reconnection, intro to MonoGame
04-MoveSync ★4 Fixed tick rate, channel separation, snapshot interpolation
05-TankBattle ★5 Client prediction / server reconciliation, lag compensation
tools/LoadTest — Load measurement (throughput, retransmit rate, RTT, GC)

Online Book

Learning Real-Time Game Networking with C# and KCP — 17 chapters + 5 appendices. (The book itself is available in Korean only.)

  • Part 1, Principles — games and networking, ARQ, anatomy of the KCP protocol
  • Part 2, Usage — getting started, the core API, sessions, choosing a channel, tuning
  • Part 3, Practice — a 1:1 match with the five samples above
  • Part 4, Depth — allocation-free performance, security, FEC, operations

Every code snippet in the book is lifted straight from the code in samples/, and the original file path is noted with every code block.

Want a deep, file-by-file walkthrough of the source itself? See docs/code-guide.md — a very detailed explanation of every file in the core and transport layer, line by line (Korean only).

Installation

# NuGet (after publishing)
dotnet add package KcpCSharpR1
dotnet add package KcpCSharpR1.Transport

# Source reference
dotnet add reference path/to/kcp-csharp/src/KcpCSharpR1/KcpCSharpR1.csproj
dotnet add reference path/to/kcp-csharp/src/KcpCSharpR1.Transport/KcpCSharpR1.Transport.csproj
Target Use for
net8.0 Servers, MonoGame clients
netstandard2.1 Godot C#, older runtimes

Even an allocation-free library will still show GC pauses if the host's GC settings are wrong. Add this to your server app's csproj.

<PropertyGroup>
  <ServerGarbageCollection>true</ServerGarbageCollection>
  <ConcurrentGarbageCollection>true</ConcurrentGarbageCollection>
  <TieredPGO>true</TieredPGO>
</PropertyGroup>

For a client (MonoGame), leave workstation GC as-is and rely on zero-copy receive (ReliableReceivedSpan) instead. Details are in Chapter 17, Operations of the book (Korean only).

NuGet Publishing (For Maintainers)

The procedure for pushing a new version to nuget.org. Only two projects are packable — src/KcpCSharpR1 and src/KcpCSharpR1.Transport (Directory.Build.props defaults IsPackable=false and turns it on only for these two).

1. Bump the Version

Change <Version> in Directory.Build.props. A two-part SemVer (e.g. 0.11) is fine — NuGet normalizes it to three parts (0.11.0) automatically.

<Version>0.11.0</Version>

2. Verify Build and Tests

dotnet build -c Release      # 0 warnings
dotnet test  -c Release      # all passing

3. Pack

dotnet pack -c Release -o artifacts/nupkg src/KcpCSharpR1/KcpCSharpR1.csproj
dotnet pack -c Release -o artifacts/nupkg src/KcpCSharpR1.Transport/KcpCSharpR1.Transport.csproj

artifacts/ is gitignored. Make it a habit to open the .nupkg and check that both targets' (net8.0/netstandard2.1) dlls and xml docs are there, along with README.md and LICENSE, and that the .nuspec's <dependencies> points at the version you intended.

4. API Key (One-Time Setup)

nuget.org profile → API Keys → Create.

  • Select Scopes: Push (new package & package version)
  • Glob Pattern: KcpCSharpR1* — scope it to just these two packages
  • Expiration: up to 365 days; reissue when it expires

Once you register the key locally, you can push without --api-key afterward (on Windows it's encrypted with DPAPI and stored at %APPDATA%\NuGet\NuGet.Config).

dotnet nuget setapikey <your_key> --source https://api.nuget.org/v3/index.json

5. Push — Core First, Transport Second

Push in this order since Transport depends on the core. The .snupkg (symbol package) is pushed automatically by the same command.

dotnet nuget push artifacts/nupkg/KcpCSharpR1.<version>.nupkg           --source https://api.nuget.org/v3/index.json
dotnet nuget push artifacts/nupkg/KcpCSharpR1.Transport.<version>.nupkg --source https://api.nuget.org/v3/index.json

A version number, once pushed, cannot be undone (you can unlist it, but not delete or reuse it). Before pushing, double-check that the files in artifacts/nupkg/ are the ones you just built.

Repository Structure

src/
  KcpCSharpR1/            Protocol core (zero dependencies)
  KcpCSharpR1.Transport/  Sockets, sessions, handshake, encryption, FEC
tests/
  KcpCSharpR1.Tests/      Unit tests
  KcpCSharpR1.SimTests/   Virtual-network scenarios + real-socket integration
benchmarks/              BenchmarkDotNet
samples/                 5 samples + LoadTest
docs/                    Online book + benchmark log + roadmap

Build and Test

dotnet build -c Release              # keep it at 0 warnings
dotnet test  -c Release              # 238 tests
dotnet test  -c Release --filter "Category!=Soak"   # skip long-running tests
dotnet run   -c Release --project benchmarks/KcpCSharpR1.Benchmarks -- --filter '*'

Lineage

This repository isn't a straight copy of the original — it's a port and rebuild in C# that follows the lineage below.

skywind3000/kcp (C, MIT) → xtaci/kcp-go (Go, MIT) → KcpCSharpR1 (C#, this repository).

Carried over Newly built
Protocol logic (ARQ, sliding window, RTO calculation, congestion control) — ported from kcp-go Transport layer (handshake, session lifecycle, scheduler)
The core 24-byte header — byte-for-byte compatible with the original AES-256-GCM encryption, Reed-Solomon FEC
5 samples + the LoadTest tool
The 17-chapter online book + 5 appendices

The protocol logic was rewritten using C# idioms (Span<byte>, ArrayPool, event-based sessions, an injectable clock), but the wire format was kept as-is. Turning on RawMode lets you talk directly to an original kcp / kcp-go server (Appendix C, Korean only).

Contributing

See CONTRIBUTING.md. Bug reports are most useful when they come with a reproducible test — the virtual-time harness (tests/KcpCSharpR1.SimTests/KcpPair.cs) makes deterministic repro possible.

License

MIT. See LICENSE.

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 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. 
.NET Core netcoreapp3.0 was computed.  netcoreapp3.1 was computed. 
.NET Standard netstandard2.1 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.
  • .NETStandard 2.1

    • No dependencies.
  • net8.0

    • No dependencies.

NuGet packages (1)

Showing the top 1 NuGet packages that depend on KcpCSharpR1:

Package Downloads
KcpCSharpR1.Transport

KcpCSharpR1 전송 계층: 소켓 I/O, 세션 수명(핸드셰이크/keepalive/종료), 프레이밍.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
0.10.0 130 8/25/2026