C++20 HTTP/1.1 subset server for Linux/WSL2, built incrementally through the guide's final milestones. The original sequential server remains available alongside a thread-per-client baseline and the default bounded pool.
Run these commands inside Ubuntu/WSL2:
sudo apt update
sudo apt install -y build-essential cmake git python3 curl
cmake -S . -B build -DCMAKE_BUILD_TYPE=Debug
cmake --build build -j4
ctest --test-dir build --output-on-failureThe first two commands install the toolchain. CMake configures an out-of-source
Debug build, --build compiles with four build jobs (unrelated to server workers),
and CTest runs six unit, integration, concurrency, and fault-injection suites.
Verified on WSL2 with GCC 15.2.0 and Python 3.14.4.
./build/server --mode pool --threads 4 --queue-capacity 64 --port 8080Use another terminal for requests:
curl -i http://127.0.0.1:8080/health
curl -I http://127.0.0.1:8080/health
curl -i "http://127.0.0.1:8080/compute?n=3"
curl -i "http://127.0.0.1:8080/sleep?ms=100"
curl -i http://127.0.0.1:8080/metrics-i includes response headers; -I sends HEAD. Compute returns a deterministic
checksum (35 for n=3); sleep simulates work that occupies a worker.
Ctrl+C stops admission, wakes the queue, and joins threads. Set a grace period
to finish admitted requests before cancelling any remaining work.
| Option | Default | Meaning |
|---|---|---|
--host |
127.0.0.1 |
IPv4 bind address |
--port |
8080 |
TCP port, 1..65535 |
--backlog |
16 |
Kernel listen backlog, 1..1024 |
--mode |
pool |
single, thread-per-client, or pool |
--threads |
4 |
Pool workers, 1..256 |
--queue-capacity |
64 |
Pending pool sockets, 1..65536 |
--max-clients |
128 |
Baseline connection-thread limit, 1..4096 |
--read-timeout-ms |
5000 |
Absolute header read deadline, 1..600000 ms |
--write-timeout-ms |
5000 |
Absolute response write deadline, 1..600000 ms |
--shutdown-grace-ms |
0 |
Drain admitted work before cancellation, 0..60000 ms |
--log-level |
info |
debug, info, warn, error, off |
--log-file |
stderr | Append JSON lines to a file instead of stderr |
--help prints usage. Pool settings apply only to pool mode; --max-clients
applies only to thread-per-client. configs/server.conf documents defaults but
is not parsed by the executable. Stop the current server before trying another:
./build/server --mode single
./build/server --mode thread-per-client --max-clients 128Reliability and logging example:
./build/server --read-timeout-ms 2000 --write-timeout-ms 2000 --shutdown-grace-ms 1000 --log-level debug --log-file server.jsonlRead deadlines begin when a worker starts a connection, not at acceptance;
write deadlines begin after routing. Partial progress never resets a deadline.
Timeouts close TCP without an HTTP response. /metrics reports queue depth,
completion/error/timeout counts, throughput, and a fixed-size latency histogram.
See reliability and observability.
listener -> bounded queue -> N workers -> Connection -> parser -> router -> response
mutex/CV | owns socket and buffers
+-- atomic counters
signal waiter -> stop source -> accept loop and connection cancellation
RAII sockets have exactly one owner. Queue operations hold their mutex only while changing queue state, never during socket I/O. Full queues immediately close excess sockets; no potentially blocking overload response runs in the accept loop. The baseline joins completed threads and caps concurrent growth. See architecture and race analysis.
GET/HEAD, selected header validation, 8192-byte header limit, Content-Length, 400/404/405/500 responses, and one response per connection are implemented. See the exact protocol specification.
python3 scripts/concurrency_demo.py build/server --output results/concurrency-demo-new.csvThis starts only localhost servers. Choose a fresh output filename for each run;
the demo script overwrites its explicit output path. The preserved early baseline
is results/concurrency-demo.csv with environment metadata in the adjacent JSON.
The comparison notes explain the measured limits.
The sustained harness and its controls are documented in
benchmark methodology.
cmake -S . -B build-final -DCMAKE_BUILD_TYPE=Release
cmake --build build-final -j4
python3 scripts/benchmark.py build-final/server --scenario matrix
python3 scripts/benchmark.py build-final/server --scenario spike --clients 250 --queue 64 --path "/sleep?ms=5" --duration 30
python3 scripts/benchmark.py build-final/server --scenario soak --clients 4 --pause 0.05 --duration 900Python 3.11+ is required. Experiments target only loopback and save unique result
directories without overwriting earlier runs. The matrix takes about 13 minutes;
the soak runs for 15 minutes. Read methodology
before interpreting results. Plotting uses matplotlib (sudo apt install python3-matplotlib).
The demo script explains the final functional presentation.
Run the full verification matrix:
python3 scripts/verify.pyThis builds Debug, Release, ASan/UBSan and TSan in separate build-verify-*
directories and runs every suite three times. It creates a new timestamped folder
under results/verification/ containing command output, source hashes, pass/fail
status, real JSON logs and metric snapshots. It never overwrites earlier evidence.
See final test report for the recorded outcome.
Repository layout: include/server/ contains interfaces, src/ implementations,
tests/unit/ pure component tests, tests/integration/ network tests, scripts/
reproduction helpers, and docs/ specifications and progress logs. doc/ holds
the local reference PDF and local guide index, both ignored by Git.
Version-controlled milestone mappings are in requirements.
Technical milestones through Week 15 are complete: all 72 final regression suite
executions passed, and the 15-minute soak completed 69,140 requests with zero errors.
The local source deliverable is results/release/final/source.tar.gz, with build
checks and a SHA-256 checksum alongside it. Raw benchmark failures remain documented.
See the final report, release checklist, and demo for results and submission steps. Final Git tagging, publication and the student's presentation require owner review. Queued sockets wait for a worker before their read deadline begins. Grace expiry can abandon responses; logs are synchronous and should use a regular file or be disabled during performance measurements. TLS, bodies, keep-alive, static files, and full HTTP compliance are outside this subset. See test plan for sanitizer commands and progress log for completed and outstanding tasks.