smux Documentation

repository·master·Indexed 23 days ago

https://github.com/xtaci/smux

A high-performance, stream-oriented multiplexing library for Golang that allows multiple logical streams to be multiplexed over a single reliable underlying connection such as TCP or KCP. It provides a Session manager, Stream implementations of the net.Conn interface, and a configurable wire format supporting protocol versions 1 and 2.

Tokens
3.2K
Snippets
9
Records
28
Agent score
82%

What's inside smux

  1. How smux architecture works

    master

    Smux (Simple MUltipleXing) is a stream-oriented multiplexing library for Golang that runs on top of a reliable, ordered connection like TCP or KCP. It uses three core abstractions:

    1. Session: The primary manager for a multiplexed connection. It manages the underlying io.ReadWriteCloser, handles the creation and acceptance of streams, and manages the shared receive buffer.
    2. Stream: A logical stream within a session. Each stream implements the net.Conn interface, allowing you to handle data buffering and flow control for individual streams independently.
    3. Frame: The wire format used for data transmission.
  2. Configure smux session parameters

    master

    You can tune the behavior of a session by passing a smux.Config object to smux.Client or smux.Server. The following configuration keys are available:

    • Version: Protocol version (1 or 2).
    • KeepAliveInterval: Interval for sending NOP frames to keep the connection alive.
    • KeepAliveTimeout: Timeout for closing the session if no data is received.
    • MaxFrameSize: Maximum size of a frame.
    • MaxReceiveBuffer: Maximum size of the shared receive buffer.
    • MaxStreamBuffer: Maximum size of the per-stream buffer.
  3. Implement a smux client

    master

    To use smux as a client, establish a standard connection (e.g., via net.Dial), then initialize a smux session using smux.Client. You can then open new logical streams within that session using session.OpenStream(). Each stream implements io.ReadWriteCloser.

    func client() {
        // Get a TCP connection
        conn, err := net.Dial(...)
        if err != nil {
            panic(err)
        }
    
        // Setup client side of smux
        session, err := smux.Client(conn, nil)
        if err != nil {
            panic(err)
        }
    
        // Open a new stream
        stream, err := session.OpenStream()
        if err != nil {
            panic(err)
        }
    
        // Stream implements io.ReadWriteCloser
        stream.Write([]byte("ping"))
        stream.Close()
        session.Close()
    }
  4. Implement a smux server

    master

    To use smux as a server, accept an underlying connection (e.g., from a net.Listener), then initialize a smux session using smux.Server. You can then accept incoming logical streams using session.AcceptStream().

    func server() {
        // Accept a TCP connection
        conn, err := listener.Accept()
        if err != nil {
            panic(err)
        }
    
        // Setup server side of smux
        session, err := smux.Server(conn, nil)
        if err != nil {
            panic(err)
        }
    
        // Accept a stream
        stream, err := session.AcceptStream()
        if err != nil {
            panic(err)
        }
    
        // Listen for a message
        buf := make([]byte, 4)
        stream.Read(buf)
        stream.Close()
        session.Close()
    }
  5. Configure smux sessions with Config

    master

    The Config struct allows you to tune the behavior of a smux session. You can use DefaultConfig() to get a sane starting point and then modify specific fields. Use VerifyConfig(config) to ensure your settings are valid before initializing a session.

    Configuration Fields:

    • Version: SMUX Protocol version (supports 1 or 2).
    • KeepAliveDisabled: If true, disables keep-alive mechanisms.
    • KeepAliveInterval: Frequency of sending NOP commands to the remote.
    • KeepAliveTimeout: Duration after which the session is closed if no data arrives.
    • MaxFrameSize: Maximum size of a single frame sent to the remote (must be $\le$ 65535).
    • MaxReceiveBuffer: Maximum total data allowed in the buffer pool.
    • MaxStreamBuffer: Maximum data allowed per individual stream (must be $\le$ MaxReceiveBuffer).
  6. Smux wire format specification

    master

    The smux wire format consists of a header and a variable-length payload.

    Header Structure:

    • VERSION (1B)
    • CMD (1B)
    • LENGTH (2B)
    • STREAMID (4B)

    Command (CMD) Values:

    • cmdSYN(0)
    • cmdFIN(1)
    • cmdPSH(2)
    • cmdNOP(3)
    • cmdUPD(4) (Supported only on version 2)

    Stream ID Rules:

    • Clients use odd numbers starting from 1.
    • Servers use even numbers starting from 0.

    Version 2 cmdUPD details: When using cmdUPD, the payload contains:

    • CONSUMED (4B)
    • WINDOW (4B)
  7. Manage multiplexed streams with Session

    master

    The Session type is the core of smux, representing a multiplexed connection that allows multiple independent streams to run over a single underlying io.ReadWriteCloser.

    Key capabilities:

    • Create new streams: Use OpenStream() to initiate a new stream on the session.
    • Accept incoming streams: Use AcceptStream() to block and wait for the peer to open a new stream.
    • Generic I/O: Both OpenStream() and AcceptStream() can be used via the Open() and Accept() methods, which return a generic io.ReadWriteCloser instead of a specific *smux.Stream.
    • Lifecycle management: Closing the session via Close() will terminate all active streams and the underlying connection.
  8. Verify smux configuration

    master

    The VerifyConfig(config *Config) function checks the sanity of a configuration object. It validates:

    • Protocol version is 1 or 2.
    • Keep-alive interval is positive (if not disabled).
    • Keep-alive timeout is greater than the interval.
    • MaxFrameSize is between 1 and 65535.
    • MaxReceiveBuffer is positive and $\le$ math.MaxInt32.
    • MaxStreamBuffer is positive, $\le$ MaxReceiveBuffer, and $\le$ math.MaxInt32.
  9. Initialize a smux Client

    master
    Use Client(conn io.ReadWriteCloser, config *Config) to create a new client-side session. It requires an existing connection that implements io.ReadWriteCloser. If config is nil, DefaultConfig() is used automatically. The function will return an error if the provided configuration fails VerifyConfig.
  10. Use the Stream type for multiplexed data transfer

    master
    The Stream type implements the net.Conn interface, allowing you to use it as a standard network connection for reading and writing data over a multiplexed session. It supports both version 1 and version 2 protocols (with version 2 providing advanced flow control) and handles frame splitting, deadlines, and half-close semantics.
  11. Initialize a smux Server

    master
    Use Server(conn io.ReadWriteCloser, config *Config) to create a new server-side session. It requires an existing connection that implements io.ReadWriteCloser. If config is nil, DefaultConfig() is used automatically. The function will return an error if the provided configuration fails VerifyConfig.
  12. Understand the cmdUPD payload format

    master

    The cmdUPD command (Protocol Version 2) uses a specific 8-byte payload format to manage flow control and acknowledgments. It is structured as follows:

    OffsetSizeDescription
    04BData consumed (ACK)
    44BWindow size (WINDOW)

    This allows the peer to notify the sender about how many bytes have been processed and the current available window size.

    // data size of cmdUPD, format:
    // |4B data consumed(ACK)| 4B window size(WINDOW) |
    const szCmdUPD = 8