Overview of Native WebSocket Client
masterNativeWebSocket.WebSocket class.repository·master·Indexed 23 days ago
https://github.com/endel/nativewebsocketA lightweight, dependency-free WebSocket client library for cross-platform .NET development. It specifically targets game engines such as Unity (2019.1+), MonoGame, and Godot, as well as generic .NET environments. The library provides an asynchronous API for connecting, sending binary or text data, and handling events like OnOpen, OnMessage, OnError, and OnClose.
NativeWebSocket.WebSocket class.The benchmarks measure several key performance indicators across different payload sizes (32B, 256B, 1KB, 8KB, 64KB):
| Benchmark | Description | Key Metrics |
|---|---|---|
| Latency | Round-trip time (send → echo → receive) | min/avg/median/p95/p99/max/stddev (ms) |
| Throughput_Send | Messages sent per second | msgs/sec, MB/sec |
| Throughput_Recv | Messages received per second (server floods) | msgs/sec, MB/sec |
| Throughput_Bidir | Simultaneous send + receive | send & recv msgs/sec |
| GCAlloc_Send | Heap allocation per Send() call | bytes/op, GC collections |
| GCAlloc_Dispatch | Heap allocation per DispatchMessageQueue() | bytes/op, GC collections |
| FrameTime_Baseline | Dispatch overhead with no traffic | avg/p99/max/jitter (ms) |
| FrameTime_Dispatch | Dispatch overhead under 50k-message flood | avg/median/p95/p99/max/jitter (ms) |
| FrameTime_UnderLoad | Total frame time during flood | avg/p99/max/jitter (ms) |
| Burst | Process 100 messages sent in <10ms | total time, peak/frame, peak frame time |
Note: The Unity BenchmarkRunner can selectively enable specific runs via runThroughputSend, runThroughputReceive, or runThroughputBidirectional.
The benchmark server is a Node.js application that acts as a WebSocket echo and flood server. It listens on ws://localhost:3000 by default. You can change the port by setting the PORT environment variable.
To start the server:
cd benchmarks/server
npm install
node index.jsThe console harness allows you to run comparisons between the old and new WebSocket implementations without opening the Unity editor. This is useful for rapid iteration on the benchmark logic itself.
cd benchmarks/ConsoleRunner
dotnet run -c ReleaseNativeWebSocket requires Unity 2019.1+ with .NET 4.x+ Runtime.
Important: Do not copy raw source files directly into your project, as the core WebSocket.cs requires build-time transformations for WebGL support. Use one of the following methods:
https://github.com/endel/NativeWebSocket.git#upm-2Note: For the legacy 1.x version, use https://github.com/endel/NativeWebSocket.git#upm.
NativeWebSocket.unitypackage from the Releases page.https://github.com/endel/NativeWebSocket.git#upm-2Use the .NET CLI to add the necessary packages:
For MonoGame:
dotnet add package Colyseus.NativeWebSocket
dotnet add package Colyseus.NativeWebSocket.MonoGameFor Godot (C#):
dotnet add package Colyseus.NativeWebSocketdotnet add package Colyseus.NativeWebSocket
dotnet add package Colyseus.NativeWebSocket.MonoGameThe 2.x version introduces several breaking changes aimed at making the library a universal .NET library.
UnityEngine. It targets netstandard2.0 and net6.0.MainThreadUtil, WaitForUpdate, and WaitForBackgroundThread have been removed. Events are now automatically dispatched via SynchronizationContext in Unity, Godot, and MonoGame. Remove any manual DispatchMessageQueue() calls from your Update() loops in these engines.Close() Signature: Close() now accepts an optional WebSocketCloseCode and string reason. Existing calls without arguments still work.IWebSocket Interface: If you implement this interface, you must now include the new methods: Connect(), Close(...), Send(...), and SendText(...)..unitypackage to ensure WebGL compatibility.| What changed | Action required |
|---|---|
MainThreadUtil / WaitForUpdate / WaitForBackgroundThread removed | Delete any code using these classes |
| Automatic event dispatching | Remove DispatchMessageQueue() from Update() (Unity/Godot/MonoGame) |
Custom IWebSocket implementations | Add Connect(), Close(), Send(), SendText() methods |
| Manual file copy installs | Switch to UPM or .unitypackage |
To test the new universal implementation:
BenchmarkNew/Assets/ into your project's Assets/ folder.BenchmarkRunner component.implementationName is set to "new".To test the legacy implementation:
BenchmarkOld/Assets/ into your project's Assets/ folder.BenchmarkRunner component.implementationName is set to "old".Use the provided Python script to aggregate multiple CSV runs and compare the performance of the old baseline against the new candidate implementation.
Available Filters:
--benchmarks: Filter by benchmark name (e.g., Throughput_Recv, FrameTime_Dispatch, Burst).--metrics: Filter by specific metrics (e.g., msgs_per_sec, avg_ms, p95_ms, p99_ms, total_time_ms).--payloads: Filter by payload sizes (e.g., 32 256 1024).python3 benchmarks/compare_results.py \
/path/to/benchmark_old_sync.csv \
/path/to/benchmark_old_sync_2.csv \
/path/to/benchmark_new_sync.csv \
/path/to/benchmark_new_sync_2.csv \
--baseline old \
--candidate newYou can run targeted Unity benchmarks (receive throughput, frame time, and burst tests) using the BenchmarkBatchRunner.RunSyncContextBenchmarks asset. This runs in Unity batchmode, writes results to a CSV, and exits.
Use the following command-line arguments to configure the run:
-benchmarkImplementation <old|new>: Select the implementation to test.-benchmarkOutput <path>: Specify the output CSV file path.-benchmarkThroughputDuration <seconds>: Duration of the throughput test.-benchmarkPayloadSizes <comma_separated_sizes>: e.g., 32,256,1024,8192,65536.In environments without a SynchronizationContext (like a standard Console application), you must manually call DispatchMessageQueue() from your main loop to process queued events.
var ws = new WebSocket("ws://localhost:3000");
ws.OnMessage += (bytes) => Console.WriteLine("Received " + bytes.Length + " bytes");
_ = ws.Connect();
while (true)
{
ws.DispatchMessageQueue();
Thread.Sleep(16);
}