async_smux

Crates.ioasync_smux
lib.rsasync_smux
version0.3.3
sourcesrc
created_at2020-10-14 05:36:54.04542
updated_at2024-01-09 15:03:55.599664
descriptionAsynchronous smux multiplexing library
homepage
repository
max_upload_size
id299535
size91,485
Black Binary (black-binary)

documentation

README

async-smux

crates.io

A lightweight asynchronous smux (Simple MUltipleXing) library for smol/async-std and any async runtime compatible to futures.

img

async-smux consumes a struct implementing AsyncRead + AsyncWrite + Unpin + Send, like TcpStream and TlsStream, to create a Mux<T> struct. And then you may spawn multiple MuxStream<T>s (up to 4294967295) over Mux<T>, which also implements AsyncRead + AsyncWrite + Unpin + Send.

Benchmark

Here is a simple benchmarking result on my local machine, comparing to the original version smux (written in go).

Implementation Throughput (TCP) Handshake
smux (go) 0.4854 GiB/s 17.070 K/s
async-smux (rust) 1.0550 GiB/s 81.774 K/s

Run cargo bench to test it by yourself. Check out /benches directory for more details.

Laziness

No thread or task will be spawned by this library. It just spawns a few futures. So it's totally runtime-independent.

Mux and MuxStream are completely lazy and will DO NOTHING if you don't poll() them.

Any polling operation, including .read() ,.write(), accept() and connect(), will push Mux and MuxStream working.

Specification

VERSION(1B) | CMD(1B) | LENGTH(2B) | STREAMID(4B) | DATA(LENGTH)

VERSION: 1

CMD:
    SYN(0)
    FIN(1)
    PSH(2)
    NOP(3)

STREAMID: Randomly chosen number

Example

use async_smux::{Mux, MuxConfig};
use async_std::net::{TcpListener, TcpStream};
use async_std::prelude::*;

async fn echo_server() {
    let listener = TcpListener::bind("0.0.0.0:12345").await.unwrap();
    let (stream, _) = listener.accept().await.unwrap();
    let mux = Mux::new(stream, MuxConfig::default());
    loop {
        let mut mux_stream = mux.accept().await.unwrap();
        let mut buf = [0u8; 1024];
        let size = mux_stream.read(&mut buf).await.unwrap();
        mux_stream.write(&buf[..size]).await.unwrap();
    }
}

fn main() {
    async_std::task::spawn(echo_server());
    async_std::task::block_on(async {
        smol::Timer::after(std::time::Duration::from_secs(1)).await;
        let stream = TcpStream::connect("127.0.0.1:12345").await.unwrap();
        let mux = Mux::new(stream, MuxConfig::default());
        for i in 0..100 {
            let mut mux_stream = mux.connect().await.unwrap();
            let mut buf = [0u8; 1024];
            mux_stream.write(b"hello").await.unwrap();
            let size = mux_stream.read(&mut buf).await.unwrap();
            let reply = String::from_utf8(buf[..size].to_vec()).unwrap();
            println!("{}: {}", i, reply);
        }
    });
}
Commit count: 0

cargo fmt