Silver9 WebSocket
A simplified high-performance low-latency Rust WebSocket client library providing three distinct implementations: async/threaded with channels, non-blocking with callbacks, and blocking with callbacks.
Features
- ⚡ Low latency - Built with Rust as a thin layer over tungstenite-rs and optional for crossbeam-channel
- 🚀 Non-blocking, Blocking, Async Channels - Choose the right approach for your use case
- 🔒 TLS backend - Support for native-tls
- 📡 Event-driven architecture - With either handler callbacks or channels
- 🎯 Type-safe API - Leverage Rust's type system for correctness
- 📊 Built-in tracing - Comprehensive logging support
- 🤖 AI Coding Ready - Support for AI-assisted development with Claude (Vibe Coding)
Design Principles
- 🕑 Predictable latency - Direct system calls and callbacks, means lower baseline latency
- 📋 Low overhead - No task scheduling, futures, or waker infrastructure
- 🤯 Simple model - Straightforward usage
- 📐 Deterministic behavior - Optional custom spin-wait duration gives precise control over CPU/latency tradeoff
- 🚫️ No runtime - No async runtime or framework overhead, no
poll()/epoll_wait()/kevent() - 🔁 Async message passing - Optional message passing through channels
- ⛔️ Graceful Shutdown - Process all messages util connection is closed by server on graceful shutdown
- 📛 Forcibly Shutdown - Break the client's event loop immediately
Disadvantages:
- Scalability - None of the clients scale to thousands of connections (see Scalability Constraints)
- CPU overhead - The fastest mode
non-blockingwithoutspin-waitutilizes 100% CPU core usage by design
Installation
Add this to your Cargo.toml:
[]
= "0.0.2"
TLS Backend Selection
The library uses native-tls.
Quick Start
Inspect examples for various usages and use cases.
Three Client Options
Choose the client that fits your application architecture:
- S9NonBlockingWebSocketClient - Runs on your thread, receive events via callbacks (lowest latency)
- S9BlockingWebSocketClient - Runs on your thread, receive events via callbacks
- S9AsyncNonBlockingWebSocketClient - Spawns background thread, receive events via channels (easiest usage)
Non-blocking Client (with handler callbacks)
Pure non-blocking client that runs on caller's thread using handler callbacks for events.
Socket Mode: Uses non-blocking socket I/O (set_nonblocking(true)) internally. The name "NonBlocking" refers to the socket I/O mode, not the behavior of run() which blocks the calling thread indefinitely.
Flushing: All send methods flush immediately after write
Key Features
- Runs entirely on caller's thread
- Receive events through handler callbacks (zero copy, zero allocation)
- Call client methods directly from handler callbacks (send, close, force_quit)
- Lowest possible latency
- Configurable CPU/latency trade-off via spin-wait duration
- Configurable socket options like TCP_NODELAY, TTL, etc
use ;
use Duration;
// Implement the handler trait
Blocking Client
Synchronous client that runs on caller's thread using handler callbacks for events.
Socket Mode: Uses blocking socket I/O (standard socket reads/writes) internally, with optional timeouts. The name "Blocking" refers to the socket I/O mode, not the behavior of run() which blocks the calling thread indefinitely (same as S9NonBlockingWebSocketClient).
Flushing: All send methods flush immediately after write
Key Features
- Runs entirely on caller's thread
- Receive events through handler callbacks (zero copy, zero allocation)
- Call client methods directly from handler callbacks (send, close, force_quit)
- Optional read/write timeouts for responsive control message handling (simulates non-blocking behavior)
- Configurable CPU/latency trade-off via spin-wait duration
- Configurable socket options like TCP_NODELAY, TTL, etc
use ;
// Implement the handler trait
Async Non-blocking Client (with channels)
Spawns a background thread for socket operations and communicates via channels.
Socket Mode: Uses non-blocking socket I/O (set_nonblocking(true)) internally. The name "NonBlocking" refers to the socket I/O mode, not the behavior of run() which returns immediately after spawning the thread.
Flushing: All send methods flush immediately after write
Key Features
- Background thread handles all socket operations
- Receive events through built-in channels (
event_rx) - Send commands through built-in channels (
control_tx) - Thread-safe for multi-threaded applications
- Configurable CPU/latency trade-off via spin-wait duration
- Configurable socket options like TCP_NODELAY, TTL, etc
use ;
use Duration;
Advanced Usage
Custom Headers
use HashMap;
let mut headers = new;
headers.insert;
headers.insert;
let client = connect_with_headers?;
Handling Ping/Pong
Non-blocking Configuration
use Duration;
// Maximum performance (no sleep between reads, high CPU usage)
let options = new?;
// Balanced (10ms sleep between reads)
let options = new?;
// Low CPU usage (100ms sleep between reads, higher latency)
let options = new?;
Accessing the Underlying Socket
All clients provide low-level access to the underlying tungstenite WebSocket for advanced use cases:
use ;
let options = new;
let mut client = connect?;
// Get immutable reference to the socket
let socket = client.get_socket;
// Get mutable reference to the socket for advanced operations
let socket_mut = client.get_socket_mut;
Note for S9AsyncNonBlockingWebSocketClient: Socket access returns Option<&WebSocket> because the socket is moved to event loop thread after calling run(). Socket access is only available before run() is called.
Use with caution: Direct manipulation of the underlying socket may interfere with the client's operation.
Logging
The library uses the 'tracing' crate for logging. Enable logging in your application: use tracing_subscriber;
fmt
.with_max_level
.init;
Performance Tips
- Choose the right client:
- Use non-blocking client for low-latency applications
- Use async client for easiest embedding in multithreaded applications
- Tune spin wait duration:
None: Best latency, highest CPU usageSome(Duration::from_millis(1-10)): Good balance for up to 100 message/secSome(Duration::from_millis(50-100)): Lower CPU, higher latency, less throughput
- Tune no_delay:
None: use OS defaultSome(true): socket write operations are immediately executedSome(false): socket write operations are scheduled by OS
Scalability Constraints
None of the clients scale to thousands of connections.
The library's architecture requires one OS thread per connection because each client's run() method either
spawns a dedicated thread (async client) or blocks the caller's thread indefinitely (non-blocking and blocking client).
There is no I/O multiplexing support to run multiple connections on a single thread.
For 1000+ connections, use async/await libraries like tokio-tungstenite or async-tungstenite that provide
true async I/O multiplexing.
API documentation
Full API documentation is available at https://docs.rs/s9_websocket/latest/s9_websocket.
Contributing
Contributions are welcome! Please feel free to submit bugs and make feature requests here Further information like coding conventions are currently maintained in CLAUDE.md
License
This project is licensed under the APACHE / MIT License - see the LICENSE files for details.
Project URL
Project source code is available at https://github.com/AlexSilver9/s9_websocket.
Authors
Acknowledgments
Built on top of: