Skip to content

theMuslimDev/pulsar

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

2 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

pulsar

My Rust Arc Begins.

A concurrent TCP echo server built to learn async Rust properly.

What it does

  • 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 HEARTBEAT frame 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

Technical stack

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

Running the server

cargo run

By 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 only

To 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 | xxd

Running the tests

cargo test

The test suite covers:

  • Unit tests in src/framing.rs — encode/decode round-trips, edge cases (empty payload, binary data, truncated input), and error paths (DecodingError on malformed frames)
  • Integration tests in tests/ — a live TcpListener spins 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 -- --nocapture

Run a specific test by name:

cargo test roundtrip_binary_data

Core patterns

Framingsrc/framing.rs Length-prefix framing: 4-byte big-endian u32 followed by exactly that many payload bytes.

Connection handlingsrc/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 stateArc<Mutex<ConnectionRegistry>> The connection registry is wrapped in Arc<Mutex<>> so it can be cloned into each task.

Graceful shutdownCancellationToken + JoinSet Ctrl+C cancels a CancellationToken that every task selects on. JoinSet::join_next drains all tasks before the process exits.

About

Concurrent async TCP echo server in Rust

Topics

Resources

License

Stars

Watchers

Forks

Contributors

Languages