rammux is a Tokio-based stream multiplexer for reliable byte stream transports.
It lets two peers run many independent bidirectional byte streams over one
AsyncRead + AsyncWrite connection while keeping stream lifecycle, per-stream flow
control, keepalive, and shutdown in one place.
When you need to handle multiple independent data streams within one byte stream transport, and that transport is not prone to HOL blocking. HOL blocking on the transport level can become a serious performance bottleneck. Instead of running ramux over a single TCP connection, you should probably rather use multiple TCP connections or QUIC.
RammuxConnection<IO>: the protocol driver that owns the transportRammuxDuplex: a virtual bidirectional byte stream- per-stream flow control with local receive window autotuning
- fair round-robin scheduling and data framing across ready streams
- graceful downgrade back to the original transport
The crate is transport-agnostic. If the type implements async reads and writes, it can carry rammux.
This crate does not spawn background tasks. Your application keeps the connection alive and working by manually polling the driver.
While you do that, the driver:
- reads inbound frames,
- writes outbound frames,
- yields new inbound streams,
- initiates and handles
PINGexchanges.
Each accepted or created stream is represented as RammuxDuplex, which
implements:
futures::Sink<bytes::Bytes>for writingfutures::Stream<Item = bytes::Bytes>for reading
If the connection stops being polled, all stream IO stalls with it.
rammux does not define an in-band handshake. Before running the protocol, the application must agree on compatible configuration and roles.
examples/negotiation.rs shows an example out-of-band negotiation flow.
Each stream has two independent receive windows, one on each side.
As the writer sends bytes, it consumes the receive window on the other side.
As the reader reads bytes, the rammux driver automatically sends WINDOW_UPDATE frames
that restore the receive window. This lets the peer continue writing.
This implementation also maintains a local global receive window pool.
Streams that sustain high throughput can temporarily borrow from that pool so the peer
spends less time waiting for window updates. RTT sampled from PING
request/response frames is used to tune the receive window toward roughly
1.5 * bandwidth-delay-product.
Those tuning details are local behavior. On the wire, the peer only sees normal
WINDOW_UPDATE frames.
rammux never shuts down the original transport. The protocol always ends with a downgrade handshake that allows for reclaiming the transport.
Usage examples live in the examples directory:
examples/negotiation.rs: negotiate config out of bandexamples/flow_control.rs: show blocked and active streams coexistingexamples/downgrade.rs: orderly shutdown and transport recoveryexamples/heavy_io.rs: compare rammux against raw transport throughput
See PROTOCOL.md for the current on-wire format.
This crate does not promise backwards compatibility across major versions.