Discrete-event simulations of four network protocols — three multiple-access / MAC-layer protocols (CSMA/CA, Slotted ALOHA, a cellular MAC scheduler with PO / WRR / WRR+PFT) and a TCP/IP stack (ICMP, UDP, TCP) — with core simulation logic written in Go and plotting in Python.
Each simulator's Go CLI writes a JSON results file; a matching Python script reads that file and renders the performance plots with matplotlib. See docs/ for the analytical background, parameter tables, and result observations behind each protocol.
- Go 1.26+
- Python 3.9+ with
numpyandmatplotlib:pip install -r requirements.txt
make csma-ca # S/G, E(N_T)/G, D/S curves for CSMA/CA
make slotted-aloha # S/G, E(N_T)/G, D/G, D/S curves across (K, N) combos
make mac-scheduler-po # throughput/delay/fairness vs. N for the PO scheduler
make mac-scheduler-wrr
make mac-scheduler-wrrpft
make tcp-ip-stack # ICMP/UDP delivery, TCP throughput/retransmissions vs. loss rate
make all # run everything
make test # go test ./...Plots are written to out/plots/; JSON results to out/. Both directories are gitignored — treat them as build artifacts, regenerate as needed.
You can also run each stage directly without make:
go run ./cmd/csma-ca -o out/csma_ca.json
python3 plot/csma_ca_plot.py out/csma_ca.json --out-dir out/plotsIEEE 802.11-style non-persistent CSMA/CA: DIFS/SIFS interframe spacing, binary exponential backoff, ACK handshake. Simulates N stations sharing a channel and sweeps offered load G, comparing against a closed-form analytical model. See docs/csma-ca.md.
go run ./cmd/csma-ca -n 12 -trials 10 -seed 1 -o out/csma_ca.jsonStations alternate between Thinking and Backlogged states; collisions trigger a uniform random backoff in [1, K]. Sweeps offered load G across a set of (K, N) combinations. See docs/slotted-aloha.md.
go run ./cmd/slotted-aloha -k 4,10 -n 4,16 -seed 1 -o out/slotted_aloha.jsonA cellular base station scheduling downlink packets for 8 mobile stations across 3 QoS traffic classes, comparing three scheduling disciplines (PO, WRR, WRR+PFT) as the number of flows N grows. See docs/mac-scheduler.md.
# Full sweep N = 1..n-total at a fixed scheme
go run ./cmd/mac-scheduler run -scheme PO -n-total 35 -minutes 5 -o out/mac_scheduler_po.json
# Single (scheme, N) point - replaces the old TCP socket server/client
go run ./cmd/mac-scheduler point -scheme PO -n 5 -minutes 5 -o -A from-scratch Go port of MiniTCP (formerly a C++ user-space stack over a Linux TUN device) as a discrete-event simulator: ICMP echo, UDP datagrams, and a full eleven-state TCP connection FSM with sliding-window data transfer and retransmission, all swept over a packet-loss rate instead of run against real sockets. See docs/tcp-ip-stack.md.
go run ./cmd/tcp-ip-stack -loss 0,0.05,0.1,0.2,0.3 -trials 10 -seed 1 -o out/tcp_ip_stack.jsonSample output from the Go implementation (-seed 1, default parameters). See docs/ for fuller discussion and the original Python projects' reference numbers.
CSMA/CA (N = 12, load swept over G ∈ [0.01, 11]):
| Peak throughput S | Load G at peak | |
|---|---|---|
| Analytical | 0.8645 | 8.82 |
| Simulation | 0.7877 | 7.90 |
Slotted ALOHA (load swept over G ∈ [0.01, 3], 5000 slots/point):
| K, N | Peak Throughput S | Load G at Peak S | Max E(N_T) | Max Delay D |
|---|---|---|---|---|
| K = 4, N = 4 | 0.412 | 0.77 | 3.9 | 10.2 |
| K = 4, N = 16 | 0.295 | 0.32 | 162.3 | 562.5 |
| K = 10, N = 4 | 0.419 | 2.77 | 2.4 | 8.9 |
| K = 10, N = 16 | 0.373 | 0.54 | 13.1 | 78.7 |
| K = 10, N = 10 | 0.393 | 0.66 | 5.5 | 28.6 |
MAC Scheduler (5 simulated minutes/point; class delays in ms except class 3, in s):
| N | Scheme | Total (Mbps) | Class 1 (Mbps / delay) | Class 2 (Mbps / delay) | Class 3 (Mbps / delay) |
|---|---|---|---|---|---|
| 1 | PO | 0.008 | 0.008 / 1.0 ms | 0.000 / 0.0 ms | 0.000 / 0.000 s |
| 5 | PO | 0.066 | 0.031 / 1.0 ms | 0.036 / 1.1 ms | 0.000 / 0.000 s |
| 10 | PO | 0.105 | 0.069 / 1.3 ms | 0.036 / 1.2 ms | 0.000 / 0.000 s |
| 11 | PO | 0.504 | 0.069 / 1.2 ms | 0.036 / 1.2 ms | 0.399 / 0.001 s |
| 15 | PO | 0.171 | 0.100 / 1.1 ms | 0.072 / 1.3 ms | 0.000 / 0.000 s |
| 20 | PO | 0.600 | 0.130 / 1.3 ms | 0.072 / 1.7 ms | 0.398 / 0.003 s |
| 35 | PO | 0.772 | 0.230 / 1.7 ms | 0.143 / 4.3 ms | 0.399 / 0.079 s |
| 5 | WRR | 0.066 | 0.031 / 101.6 ms | 0.036 / 17.3 ms | 0.000 / 0.000 s |
| 10 | WRR | 0.105 | 0.069 / 84.0 ms | 0.036 / 60.8 ms | 0.000 / 0.000 s |
| 15 | WRR | 0.171 | 0.100 / 205.3 ms | 0.072 / 75.0 ms | 0.000 / 0.000 s |
| 5 | WRR+PFT | 0.066 | 0.031 / 101.6 ms | 0.036 / 17.3 ms | 0.000 / 0.000 s |
| 10 | WRR+PFT | 0.105 | 0.069 / 84.0 ms | 0.036 / 60.8 ms | 0.000 / 0.000 s |
| 15 | WRR+PFT | 0.171 | 0.100 / 205.3 ms | 0.072 / 75.0 ms | 0.000 / 0.000 s |
The N = 11 jump and N = 15 dip in PO's total throughput are the apportionment artifact described in docs/mac-scheduler.md, not a bug — a third class-3 flow enters and leaves the mix as flow counts get re-rounded per N.
TCP/IP Stack (-seed 1, default parameters; throughput in bytes/tick, retransmissions/segments per 65536-byte transfer):
| Loss rate | ICMP delivered | UDP delivered | TCP throughput | TCP retransmissions |
|---|---|---|---|---|
| 0.00 | 1.000 | 1.000 | 5461.3 | 0.0 |
| 0.05 | 0.883 | 0.946 | 4551.7 | 1.1 |
| 0.10 | 0.823 | 0.914 | 2665.4 | 5.4 |
| 0.20 | 0.654 | 0.796 | 1418.4 | 12.4 |
| 0.30 | 0.473 | 0.704 | 1112.9 | 17.8 |
ICMP's delivery ratio falls off faster than UDP's at the same loss rate because an echo reply requires both the request and reply leg to survive ((1-p)²), while a UDP datagram only crosses the link once.
cmd/ Go CLI entrypoints, one per protocol (each with its own JSON envelope/result types)
internal/
csmaca/ CSMA/CA state machine, simulator, analytical model
macscheduler/ Cell, Flow, BaseStation, scheduling schemes
slottedaloha/ Station state machine, simulator
tcpipstack/ IP/checksum substrate, ICMP/UDP/TCP sweeps, TCP connection FSM
plot/ Python plotting scripts, one per protocol (each self-contained)
docs/ Per-protocol analytical background and results
Each of the four simulators (CLI, internal package, plot script) is fully self-contained and shares no code with the others — small helpers like linspace/mean/stddev and the JSON envelope writer are duplicated locally rather than factored into a shared package.
The first three simulators don't have seeded RNG in their original Python form, and Go's math/rand can't bit-match Python's random regardless; the TCP/IP stack has no Python original at all — it's a discrete-event redesign of a C++ live-networking project (see docs/tcp-ip-stack.md). Correctness is verified at three tiers:
- Deterministic logic (backoff window formulas, Hamilton apportionment, the CSMA/CA analytical model, the TCP connection FSM's state transitions, RFC 1071 checksum arithmetic) is unit-tested in Go and, where no RNG is involved, cross-checked exactly against a known-good reference (the original Python output, or a worked RFC example for checksums).
- RNG-driven simulation output is checked for plausible ranges and monotonicity (e.g. TCP retransmissions rising and throughput falling as loss rate increases) against known reference curves/tables from the original projects' READMEs where one exists.
- Curve shape — generated plots are visually compared against the previously-committed reference plots for the same qualitative behavior (e.g. the MAC scheduler's throughput-vs-N apportionment dip/spike, CSMA/CA's throughput plateau, Slotted ALOHA's congestion collapse at insufficient backoff, ICMP's steeper delivery falloff vs. UDP's single-leg loss).