SocketSignal 2.0.0

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

SocketSignal

NuGet .NET License CI

Bidirectional realtime RPC over raw WebSockets for .NET 10. A client calls methods on the server and gets return values back; the server calls methods on one client, a group, or all of them. The protocol is small enough that a browser can speak it in ten lines of JavaScript, and the .NET implementation encodes and decodes it without allocating.

Bahasa Indonesia · Documentation · Protocol · Client SDKs

The sonar console: a plan position indicator and a bearing-time recorder, both fed over SocketSignal

The example application: a sea sonar simulator built with Avalonia. Everything it draws arrives over SocketSignal from a server in the same process — read more.


Install

dotnet add package SocketSignal

Quick start

using SocketSignal;

// ---- server ----
var server = new SocketSignalServer("http://localhost:8080/ws/");

// Arguments deserialise straight into int. No JsonElement, no boxing.
server.Register<int, int, int>("sum", (client, a, b) => ValueTask.FromResult(a + b));

_ = server.StartAsync();

// ---- client ----
var client = new SocketSignalClient();

// A method the server may call on us.
client.On<string, string>("serverHello", text =>
{
    Console.WriteLine(text);
    return ValueTask.FromResult("client received");
});

await client.ConnectAsync(new Uri("ws://localhost:8080/ws/"));

int total = await client.CallAsync<int>("sum", 5, 7);        // 12

// ---- server talking back ----
await server.BroadcastAsync("serverHello", "all hands");                   // everyone
await server.SendToClientAsync(someId, "serverHello", "just for you");     // one client
await server.SendToGroupAsync("operators", "serverHello", "ops only");     // a group
int answer = await server.CallClientAsync<int>(someId, "double", 21);      // and with a result

Run the walkthrough:

dotnet run --project src/SocketSignal.Demo      # server + two clients + a round-trip measurement
dotnet run --project src/SocketSignal.SonarDemo # the Avalonia sonar console

What it does

Feature
1 Client calls a method on the server
2 Client calls a method on the server and gets a return value
3 Server calls a method on every client (broadcast)
4 Server calls a method on one client, by id — with a return value
5 Server calls a method on a group of clients

And the things a realtime library needs before it can be trusted with a connection:

  • Calls time out instead of parking the caller forever, and pending calls fail when the socket drops rather than hanging.
  • Errors travel. A handler that throws surfaces as SignalInvocationException on the caller, with the remote message. An unknown method raises MethodNotFoundException.
  • Keepalive at the protocol level, so every SDK — browser included — sees the same liveness signal, plus idle eviction on the server.
  • Auto-reconnect with exponential backoff, off by default.
  • Groups that are lock-free and clean themselves up when a client disconnects.
  • An authentication hook to vet the upgrade request before it becomes a connection.
  • Per-connection state (client.Items) and live statistics for frames, bytes and calls.
  • Backpressure: a peer that floods faster than handlers drain stops being read.

Full API in docs/api-reference.md.

Performance

v2 is a rewrite of the codec and the connection pump. Every number below is measured on this repository — reproduce them with dotnet run -c Release --project src/SocketSignal.Benchmarks.

End-to-end RPC round trips over a loopback WebSocket (20,000 sequential calls, .NET 10.0.11, Windows 11, 8 logical cores):

stack calls/sec latency allocated per call
v1 6,809 146.9 µs 16,379 B
v2 9,989 100.1 µs 3,311 B
×1.47 −32% −79.8%

The codec paths, per operation:

operation v1 time v2 time v1 allocated v2 allocated
encode one invoke frame 1,386 ns 327 ns 1,200 B 0 B
encode, single typed argument 269 ns 0 B
decode one invoke frame 1,119 ns 314 ns 1,296 B 0 B
decode and read both arguments 609 ns 0 B
find the handler for a method 52.8 ns 21.8 ns 64 B 0 B
mint a correlation id 118 ns 130 ns 88 B 0 B

Where the wins come from — and why the end-to-end figure is not zero either — is written up in docs/performance.md.

Client SDKs

The protocol is JSON over a plain WebSocket, so anything that speaks WebSocket can join in. Three SDKs ship with the same shape as the .NET client:

Language Package Dependencies
Python socketsignal websockets
Node.js socketsignal none — Node 22's global WebSocket
Go socketsignal github.com/coder/websocket
client = SocketSignalClient()

@client.on("serverHello")
async def hello(text): return "python heard you"

await client.connect("ws://localhost:8080/ws/")
print(await client.call("sum", 5, 7))          # 12
const client = new SocketSignalClient();
client.on("serverHello", (text) => "node heard you");
await client.connect("ws://localhost:8080/ws/");
console.log(await client.call("sum", 5, 7));   // 12
client := socketsignal.New(socketsignal.Options{})
client.On("serverHello", func(args []json.RawMessage) (any, error) { return "go heard you", nil })
_ = client.Connect(ctx, "ws://localhost:8080/ws/")

var total int
_ = client.Call(ctx, &total, "sum", 5, 7)      // 12

And a browser needs no SDK at all:

<script>
const ws = new WebSocket("ws://localhost:8080/ws/");

ws.onmessage = (ev) => {
  const msg = JSON.parse(ev.data);
  if (msg.type === "invoke" && msg.method === "serverHello") {
    ws.send(JSON.stringify({ type: "result", id: msg.id, result: "hello from the browser" }));
  }
};

function sum(a, b) {
  ws.send(JSON.stringify({ type: "invoke", id: "1", method: "sum", args: [a, b], expectReturn: true }));
}
</script>

See docs/clients.md.

The example application

Selecting a contact and asking the array to classify it

A sea sonar simulator. The array is a SocketSignalServer that keeps the sea state and pushes a frame to the operators group twenty times a second; the console is a SocketSignalClient that draws two instruments from it — a plan position indicator and a bearing-time recorder. Selecting a contact and pressing Classify is a client-to-server call with a return value; Active ping is another. Nothing on screen is read from local memory, so the demo actually exercises the library rather than illustrating it. docs/sonar-demo.md

Documentation

Getting started Install, first server, first client
API reference Every public type and method
Protocol The wire format, in full
Architecture How the pump, codec and dispatch fit together
Performance What was optimised, measured, and what still allocates
Client SDKs Python, Go, Node.js and the browser
Sonar demo The example application, and its design

Indonesian: docs/id/

Repository layout

src/SocketSignal/             the library
src/SocketSignal.Demo/        console walkthrough; `-- serve` runs a server for the SDK examples
src/SocketSignal.SonarDemo/   the Avalonia sonar console
src/SocketSignal.Benchmarks/  BenchmarkDotNet suite, plus the v1 baseline it measures against
tests/SocketSignal.Tests/     protocol and end-to-end tests
clients/{python,go,nodejs}/   client SDKs
docs/                         documentation, English and Indonesian

Building

dotnet build SocketSignal.slnx
dotnet test tests/SocketSignal.Tests/SocketSignal.Tests.csproj
dotnet run -c Release --project src/SocketSignal.Benchmarks -- throughput

Requires the .NET 10 SDK. On Windows, an HttpListener prefix other than localhost needs a URL ACL reservation.


<a name="bahasa-indonesia"></a>

SocketSignal — Bahasa Indonesia

Komunikasi realtime dua arah berbasis WebSocket murni untuk .NET 10. Client dapat memanggil method di server dan menerima nilai baliknya; server dapat memanggil method di satu client, satu grup, atau semua client. Protokolnya cukup sederhana sehingga browser bisa bicara langsung dengan sepuluh baris JavaScript, dan implementasi .NET-nya melakukan encode dan decode tanpa alokasi.

Instalasi

dotnet add package SocketSignal

Cara pakai

using SocketSignal;

// ---- server ----
var server = new SocketSignalServer("http://localhost:8080/ws/");

// Argumen langsung dideserialisasi menjadi int. Tanpa JsonElement, tanpa boxing.
server.Register<int, int, int>("sum", (client, a, b) => ValueTask.FromResult(a + b));

_ = server.StartAsync();

// ---- client ----
var client = new SocketSignalClient();

client.On<string, string>("serverHello", text =>
{
    Console.WriteLine(text);
    return ValueTask.FromResult("client received");
});

await client.ConnectAsync(new Uri("ws://localhost:8080/ws/"));

int total = await client.CallAsync<int>("sum", 5, 7);        // 12

// ---- server memanggil client ----
await server.BroadcastAsync("serverHello", "semua unit");                  // semua client
await server.SendToClientAsync(someId, "serverHello", "khusus kamu");      // satu client
await server.SendToGroupAsync("operators", "serverHello", "grup ops");     // satu grup
int hasil = await server.CallClientAsync<int>(someId, "double", 21);       // dan menerima balikan

Menjalankan contoh:

dotnet run --project src/SocketSignal.Demo      # server + dua client + pengukuran round-trip
dotnet run --project src/SocketSignal.SonarDemo # konsol sonar Avalonia

Fitur utama

Fitur
1 Client memanggil method di server
2 Client memanggil method di server dan menerima nilai balik
3 Server memanggil method ke semua client (broadcast)
4 Server memanggil method ke satu client berdasarkan id — dengan nilai balik
5 Server memanggil method ke satu grup client

Ditambah hal-hal yang dibutuhkan sebuah library realtime agar layak dipercaya memegang koneksi:

  • Timeout pada setiap panggilan, bukan menggantung selamanya, dan panggilan yang sedang berjalan akan gagal dengan jelas ketika socket terputus.
  • Error ikut terkirim. Handler yang melempar exception muncul sebagai SignalInvocationException di sisi pemanggil. Method yang tidak dikenal menghasilkan MethodNotFoundException.
  • Keepalive di level protokol, sehingga semua SDK — termasuk browser — melihat sinyal keaktifan yang sama, plus pemutusan koneksi yang menganggur di sisi server.
  • Auto-reconnect dengan backoff eksponensial (nonaktif secara bawaan).
  • Grup tanpa lock yang membersihkan dirinya sendiri saat client terputus.
  • Hook autentikasi untuk memeriksa permintaan upgrade sebelum menjadi koneksi.
  • State per koneksi (client.Items) dan statistik langsung untuk frame, byte, dan panggilan.
  • Backpressure: peer yang mengirim lebih cepat daripada kemampuan handler akan berhenti dibaca.

Referensi lengkap: docs/id/api-reference.md.

Performa

v2 adalah penulisan ulang pada codec dan pompa koneksi. Semua angka di bawah diukur langsung di repositori ini — jalankan sendiri dengan dotnet run -c Release --project src/SocketSignal.Benchmarks.

Round-trip RPC lengkap melalui WebSocket loopback (20.000 panggilan berurutan, .NET 10.0.11, Windows 11, 8 core logis):

versi panggilan/detik latensi alokasi per panggilan
v1 6.809 146,9 µs 16.379 B
v2 9.989 100,1 µs 3.311 B
×1,47 −32% −79,8%

Jalur codec, per operasi:

operasi waktu v1 waktu v2 alokasi v1 alokasi v2
encode satu frame invoke 1.386 ns 327 ns 1.200 B 0 B
encode, satu argumen bertipe 269 ns 0 B
decode satu frame invoke 1.119 ns 314 ns 1.296 B 0 B
decode dan baca kedua argumen 609 ns 0 B
mencari handler sebuah method 52,8 ns 21,8 ns 64 B 0 B
membuat correlation id 118 ns 130 ns 88 B 0 B

Penjelasan lengkapnya — termasuk mengapa angka end-to-end tidak nol — ada di docs/id/performance.md.

SDK client

Protokolnya JSON di atas WebSocket biasa, jadi apa pun yang bisa bicara WebSocket dapat ikut serta. Tiga SDK disertakan dengan bentuk API yang sama seperti client .NET:

Bahasa Paket Dependensi
Python socketsignal websockets
Node.js socketsignal tidak ada — WebSocket bawaan Node 22
Go socketsignal github.com/coder/websocket

Browser bahkan tidak memerlukan SDK sama sekali — lihat contoh JavaScript di bagian Inggris di atas, atau docs/id/clients.md.

Aplikasi contoh

Simulator sonar laut. Array sonar adalah SocketSignalServer yang menyimpan keadaan laut dan mengirim frame ke grup operator dua puluh kali per detik; konsolnya adalah SocketSignalClient yang menggambar dua instrumen dari data itu — sebuah plan position indicator dan sebuah bearing-time recorder. Memilih sebuah kontak lalu menekan Classify adalah panggilan client-ke-server yang menunggu nilai balik. Tidak ada satu pun yang dibaca dari memori lokal, sehingga demo ini benar-benar menguji library, bukan sekadar menggambarkannya. docs/id/sonar-demo.md

Dokumentasi

Memulai Instalasi, server pertama, client pertama
Referensi API Seluruh tipe dan method publik
Protokol Format wire secara lengkap
Arsitektur Bagaimana pompa, codec, dan dispatch bekerja sama
Performa Apa yang dioptimalkan, hasil ukurnya, dan sisa alokasinya
SDK client Python, Go, Node.js, dan browser
Demo sonar Aplikasi contoh dan rancangan visualnya

License

MIT. See LICENSE.

Dibuat oleh Gravicode Studios, dipimpin oleh Kang Fadhil.

Kalau project ini membantu, boleh traktir pulsa ke saya di: https://studios.gravicode.com/products/budax

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

    • No dependencies.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
2.0.0 70 9/2/2026

v2.0.0 - Rewritten for throughput and memory: hand-written UTF-8 codec on Utf8JsonReader/Utf8JsonWriter (no intermediate strings), pooled per-connection buffers, zero-allocation method dispatch, typed Register/Call overloads, serialized sends, call timeouts and error propagation, keepalive, auto-reconnect, public server-to-client calls with return values, and connection statistics. Targets .NET 10.