net-mux is an asynchronous connection multiplexing library built on
Tokio. It turns a single ordered, connection-oriented byte stream
(TCP, TLS-over-TCP, KCP, ...) into many concurrent bidirectional logical
streams.
- Credit-based per-stream flow control. Slow consumers do not stall
other streams; total memory is bounded by
max_streams * initial_stream_window. - Correct
AsyncRead/AsyncWrite. Large user writes are transparently fragmented; back-pressure surfaces asPoll::Pending. - Half-close.
shutdown()closes only the write half, mirroring TCP semantics. - Keepalive. Periodic
Pingframes with timeout-driven session shutdown. - Graceful close.
Session::close().awaitflushes outstanding frames, emits aGoAway, and joins all background tasks. - Lock-free hot paths. Atomic windows, atomic stream state, single outbound queue.
See docs/architecture.md and
docs/protocol.md for the deeper design notes.
use net_mux::{Config, Session};
use tokio::io::{AsyncReadExt, AsyncWriteExt};
use tokio::net::TcpStream;
#[tokio::main]
async fn main() -> anyhow::Result<()> {
let conn = TcpStream::connect("127.0.0.1:7777").await?;
let session = Session::client(conn, Config::default());
let mut stream = session.open().await?;
stream.write_all(b"hello\n").await?;
stream.shutdown().await?;
let mut buf = Vec::new();
stream.read_to_end(&mut buf).await?;
println!("{}", String::from_utf8_lossy(&buf));
session.close().await;
Ok(())
}$ cargo run --example tcp_server
$ cargo run --example tcp_clientThe server echoes each line received over a fresh multiplexed stream; the client reads stdin, opens one stream per line, and prints the reply.
$ cargo run --example forward_server # listens on :7777 (transport) and :8001 (proxy)
$ cargo run --example forward_client # connects to :7777, forwards to :8000If you start an HTTP service on 127.0.0.1:8000
(e.g. python -m http.server 8000), it becomes reachable on
http://127.0.0.1:8001 via the tunnel.
use net_mux::Config;
use std::time::Duration;
let cfg = Config::builder()
.initial_stream_window(512 * 1024)
.max_frame_size(64 * 1024)
.max_streams(2048)
.keepalive_interval(Some(Duration::from_secs(30)))
.build();