Files
2025-12-22 17:52:04 +08:00

176 lines
6.0 KiB
Markdown

<img src="assets/smux.png" alt="smux" height="35px" />
[![GoDoc][1]][2] [![MIT licensed][3]][4] [![Build Status][5]][6] [![Go Report Card][7]][8] [![Coverage Statusd][9]][10] [![Sourcegraph][11]][12]
<img src="assets/mux.jpg" alt="smux" height="120px" />
[1]: https://godoc.org/github.com/xtaci/smux?status.svg
[2]: https://godoc.org/github.com/xtaci/smux
[3]: https://img.shields.io/badge/license-MIT-blue.svg
[4]: LICENSE
[5]: https://img.shields.io/github/created-at/xtaci/smux
[6]: https://img.shields.io/github/created-at/xtaci/smux
[7]: https://goreportcard.com/badge/github.com/xtaci/smux
[8]: https://goreportcard.com/report/github.com/xtaci/smux
[9]: https://codecov.io/gh/xtaci/smux/branch/master/graph/badge.svg
[10]: https://codecov.io/gh/xtaci/smux
[11]: https://sourcegraph.com/github.com/xtaci/smux/-/badge.svg
[12]: https://sourcegraph.com/github.com/xtaci/smux?badge
[English](README.md) | [中文](README_zh-cn.md)
## Introduction
Smux (**S**imple **MU**ltiple**X**ing) is a multiplexing library for Golang. It relies on an underlying connection to provide reliability and ordering, such as TCP or [KCP](https://github.com/xtaci/kcp-go), and provides stream-oriented multiplexing. This library was originally designed to power connection management for [kcp-go](https://github.com/xtaci/kcp-go).
## Features
1. ***Token bucket*** controlled receiving, providing a smoother bandwidth graph (see picture below).
2. Session-wide receive buffer shared among streams for **fully controlled** overall memory usage.
3. Minimized header (8 bytes), maximized payload.
4. Battle-tested on millions of devices in [kcptun](https://github.com/xtaci/kcptun).
5. Built-in fair queue traffic shaping.
6. Per-stream sliding window for congestion control (protocol version 2+).
![smooth bandwidth curve](assets/curve.jpg)
## Architecture
* **Session**: The main manager for a multiplexed connection. It manages the underlying `io.ReadWriteCloser`, handles stream creation/acceptance, and manages the shared receive buffer.
* **Stream**: A logical stream within a session. It implements the `net.Conn` interface, handling data buffering and flow control.
* **Frame**: The wire format for data transmission.
## Frame Allocator
`alloc.go` implements a slab-style allocator tuned for frames up to 64 KB. Seventeen `sync.Pool` buckets cache power-of-two slice capacities, and a De Bruijn based `msb()` lookup picks the smallest bucket that can satisfy a request in constant time. Buffers are deliberately reused without zeroing, so each new frame simply overwrites the previous payload without paying the Go runtime's memclr cost.
Benefits for the session:
1. Bounded fragmentation (each request wastes < 50%) keeps the shared receive buffer predictable under load.
2. Reuse of pre-sized slices drastically lowers GC pressure and removes repeated zeroing work.
3. Constant-time bucket selection avoids locks or searches, so high-throughput sessions keep tail latency steady even with thousands of flows.
## Documentation
For complete documentation, see the associated [Godoc](https://godoc.org/github.com/xtaci/smux).
## Benchmark
```
$ go test -v -run=^$ -bench .
goos: darwin
goarch: amd64
pkg: github.com/xtaci/smux
BenchmarkMSB-4 30000000 51.8 ns/op
BenchmarkAcceptClose-4 50000 36783 ns/op
BenchmarkConnSmux-4 30000 58335 ns/op 2246.88 MB/s 1208 B/op 19 allocs/op
BenchmarkConnTCP-4 50000 25579 ns/op 5124.04 MB/s 0 B/op 0 allocs/op
PASS
ok github.com/xtaci/smux 7.811s
```
## Specification
```
+---------------+---------------+-------------------------------+
| VERSION (1B) | CMD (1B) | LENGTH (2B) |
+---------------+---------------+-------------------------------+
| STREAMID (4B) |
+---------------------------------------------------------------+
| |
/ DATA (Variable) /
| |
+---------------------------------------------------------------+
VALUES FOR LATEST VERSION:
VERSION:
1/2
CMD:
cmdSYN(0)
cmdFIN(1)
cmdPSH(2)
cmdNOP(3)
cmdUPD(4) // only supported on version 2
STREAMID:
client use odd numbers starts from 1
server use even numbers starts from 0
cmdUPD:
| CONSUMED(4B) | WINDOW(4B) |
```
## Usage
```go
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()
}
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()
}
```
## Configuration
`smux.Config` allows tuning the session parameters:
* `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.
## Reference
* [hashicorp/yamux](https://github.com/hashicorp/yamux)
* [xtaci/kcp-go](https://github.com/xtaci/kcp-go)
* [xtaci/kcptun](https://github.com/xtaci/kcptun)