My Rust Arc Begins.
A concurrent TCP echo server built to learn async Rust properly.
- Accepts multiple TCP connections concurrently, each handled in its own Tokio task
- Echoes frames back to the sender using length-prefix framing (4-byte big-endian length + payload)
- Sends a
HEARTBEATframe to clients that go silent beyond the configured interval - Reports all active connections on a fixed interval via structured logs
- Shuts down cleanly on Ctrl+C: cancels all tasks, waits for them to finish, then exits
| Concern | Choice |
|---|---|
| Compiler | rustc 1.85.0 |
| Runtime | Tokio (multi-threaded) |
| Framing | Length-prefix (4-byte big-endian u32) |
| Shared state | Arc<Mutex<T>> |
| Shutdown | tokio::signal + CancellationToken |
| Logging | tracing + tracing-subscriber |
cargo runBy default the server binds to 127.0.0.1:8080. Log verbosity is controlled via
the RUST_LOG environment variable:
RUST_LOG=info cargo run # startup, connections, disconnections, registry reports
RUST_LOG=debug cargo run # everything above + heartbeats + task lifecycle
RUST_LOG=pulsar=debug cargo run # debug for this crate onlyTo send a frame manually:
# Send a length-prefixed "HELLO" frame and read the echo back
printf '\x00\x00\x00\x05HELLO' | nc 127.0.0.1 8080 | xxdcargo testThe test suite covers:
- Unit tests in
src/framing.rs— encode/decode round-trips, edge cases (empty payload, binary data, truncated input), and error paths (DecodingErroron malformed frames) - Integration tests in
tests/— a liveTcpListenerspins up on a random port, a real TCP client connects, sends a frame, and asserts the echoed response matches
Run with output visible (useful when a test fails):
cargo test -- --nocaptureRun a specific test by name:
cargo test roundtrip_binary_dataFraming — src/framing.rs Length-prefix framing: 4-byte big-endian u32
followed by exactly that many payload bytes.
Connection handling — src/connection.rs Each connection runs in a
tokio::spawn'd task and loops on a select! with three branches: incoming
data, heartbeat timer, and cancellation signal. All log events from a
connection are tagged with the client address via a tracing::info_span!.
Shared state — Arc<Mutex<ConnectionRegistry>> The connection registry is
wrapped in Arc<Mutex<>> so it can be cloned into each task.
Graceful shutdown — CancellationToken + JoinSet Ctrl+C cancels a
CancellationToken that every task selects on. JoinSet::join_next drains all
tasks before the process exits.