Skip to content
dream-net
reference

Compatibility and performance

What the version promises, the supported Rust, the pinned dependencies, the license and notices, what is tested, and what the transport costs.

Versions#

dream-net is at 1.x: releases in 1.x keep the Rust API compatible, as Cargo’s semver rules expect. A minor release, like 1.1.0, adds API; a patch release only fixes.

Peers must speak the same wire version, and share a schema fingerprint. Builds with different WIRE_VERSIONs refuse each other with ProtocolMismatch, on both ends, rather than misreading each other. 1.0.0 and 1.1.0 speak wire format 2.

Rust and dependencies#

  • Rust 1.88 or newer, declared as rust-version and checked in CI. Edition 2024.
  • No unsafe code: the crate is #![forbid(unsafe_code)].
  • No features. Everything is always built.
DependencyVersionFor
netcode-official (netcode)=1.0.0Connect tokens, encryption, slots, timeouts
reliable=1.3.4Acknowledgements, fragmentation, link statistics
serialize-official (serialize)=2.4.0Bit-packing the wire format
sha20.11, no default featuresThe schema fingerprint

The three Más Bandwidth crates are pinned exactly, because they define what goes on the wire. An upgrade is a deliberate change that reruns the golden, fuzz and soak tests. Any sha2 0.11 computes the same digest.

License#

dream-net is MIT OR Apache-2.0, at your option.

netcode, reliable and serialize are Más Bandwidth LLC’s, under BSD 3-clause terms. Their notices are in NOTICE.md, and must travel with any product that ships dream-net, with the credit line it gives.

What is tested#

Every push runs StroggForge’s library workflow: the tests on Windows, Linux, and macOS on both Apple silicon and Intel; rustfmt; Clippy at the pedantic level with warnings as errors; cargo audit; a check against Rust 1.88; and a dry run of the crates.io publish. A tag publishes to crates.io, and attaches the Criterion results to its GitHub release as BENCHMARKS.md.

SuiteCovers
Unit and property testsSequence ordering across the wrap, schema ids and fingerprints, transport validation
tests/wire.rs, tests/wire_golden.rsRound trips against serialize’s own streams, every malformed class, every truncation, random bytes, and the golden packets
tests/connection.rsOver the simulator: exactly-once ordered delivery under loss, reordering and duplication, id wrap, fragments, the handshake and both mismatches, malformed input, backpressure, the parked budget, acknowledgement bursts
tests/netcode.rsServer and Client over localhost UDP: connecting, exchanging, disconnecting, mismatches, full servers, bad tokens, silent peers, reused slots, and Connected before the first event
tests/capture.rsCapture round trips, hostile capture files, a live server’s capture
tests/alloc.rsWarm send and receive paths allocate nothing, under a counting allocator
tests/fuzz_smoke.rsThe five fuzz harnesses on the stable toolchain
tests/soak.rsSixteen pairs for 1500 frames: mixed channels, loss, jitter, duplication, fragments, reconnects, stalled polling and id wrap, checking delivery and memory throughout

Two gates run longer than cargo test does:

DREAM_NET_SOAK_FRAMES=200000 cargo test --release --test soak -- --nocapture
cd fuzz && RUSTC_BOOTSTRAP=1 cargo fuzz run <target> -s none -O -- -max_total_time=600

The fuzz targets are wire_decode, connection_stream, channel_schedule, handshake and capture_read. They run on the stable toolchain, which is what RUSTC_BOOTSTRAP is for.

What it costs#

Criterion means from the benchmarks CI ran for 1.0.0, on a GitHub ubuntu-22.04 runner, from the BENCHMARKS.md on its GitHub release. cargo bench --bench <name> runs one suite: wire, connection, scale or netcode.

Per call#

Call (connection/…)16 B64 B256 B1024 B
send, reliable18.2 ns19.2 ns22.1 ns62.4 ns
send, unreliable17.0 ns17.7 ns20.9 ns60.8 ns
poll_into6.1 ns8.2 ns23.7 ns

256 events through one connection#

Benchmark16 B64 B256 B1024 B
pack: queued events into datagrams, reliable8.2 µs10.2 µs17.9 µs52.5 µs
pack, unreliable7.1 µs8.9 µs17.0 µs54.1 µs
direct: a full frame on both ends, reliable25.9 µs29.5 µs47.1 µs126.6 µs
direct, unreliable23.0 µs25.8 µs42.3 µs117.6 µs

Sixteen 8 KiB reliable events, fragmented and reassembled, take 31.7 µs. An idle connection’s update costs 2.1 µs, and an idle frame on both ends 4.5 µs.

Loss#

20,000 reliable 64-byte events through the simulator, 50 ms each way with 10 ms of jitter, resends included:

Loss0%1%5%20%
Time7.04 ms7.10 ms7.45 ms8.45 ms

Many peers#

One server’s frame, with each client sending a 16-byte reliable event and a 64-byte unreliable one, and the server sending each client the same plus a 64-byte state event, datagrams passed directly:

Peers11664256
Frame0.01 ms0.09 ms0.37 ms1.50 ms
Idle frame0.29 ms1.15 ms

Real sockets#

Loopback UDP with netcode’s encryption, each client sending 32 64-byte events a frame and the server sending 32 back to each, against netcode alone sending one datagram per event:

Clients1832
dream-net0.06 ms0.49 ms1.94 ms
One datagram per event0.65 ms5.15 ms19.87 ms

Aggregation is most of the difference: one encryption and one system call per packet instead of per event.

The codec#

Encoding and decoding one packet (wire/…), reliable:

PacketEncodeDecode
1 × 16 B26.6 ns25.4 ns
8 × 64 B116.9 ns93.1 ns
16 × 256 B253.6 ns167.7 ns
64 × 64 B843.0 ns633.9 ns
4 × 1024 B101.1 ns53.8 ns

Decoding copies nothing: payloads stay in the packet until they are delivered.