How frp TCP Stream Multiplexing Improves Performance and Reduces Latency
frp uses the Yamux library to multiplex multiple logical proxy streams over a single TCP connection, eliminating per-request handshake overhead and reducing latency by reusing an established congestion-controlled socket.
frp (Fast Reverse Proxy) is an open-source reverse proxy application that enables exposing local servers behind NATs to the internet. One of its key performance optimizations is frp TCP stream multiplexing, which allows multiple proxy connections to share a single underlying TCP socket between the client (frpc) and server (frps).
What Is frp TCP Stream Multiplexing?
TCP stream multiplexing in frp is implemented via the TCPMux feature, which leverages the Yamux library to create many logical streams over one physical TCP connection. Instead of opening a new TCP socket for every proxy request, frp maintains a persistent session and opens lightweight streams within it.
This approach eliminates the TCP three-way handshake and TLS negotiation for every new proxy connection, significantly reducing connection establishment time and CPU overhead.
Performance Benefits of TCP Stream Multiplexing in frp
The following table summarizes how TCPMux improves performance and reduces latency:
| TCPMux Capability | Performance Impact |
|---|---|
| Reuses one TCP socket for all proxy connections | Eliminates TCP handshake and TLS setup per request, saving round-trip time and CPU cycles |
Maintains persistent connections with configurable TCPMuxKeepaliveInterval |
Prevents idle timeouts, allowing subsequent streams to start instantly without connection setup |
| Shares congestion-control state (window size, RTT, loss recovery) across streams | Improves throughput for many small streams by leveraging an already-trained congestion window |
Aggregates traffic on a single port via TCPMuxHTTPConnectPort |
Reduces kernel socket overhead and simplifies NAT/firewall configuration |
| Enables per-proxy routing via the TCPMux group controller | Allows multiple domains or users to share one multiplexed connection while remaining logically isolated |
How frp Implements TCP Stream Multiplexing
frp's multiplexing architecture involves coordinated configuration on both client and server sides, utilizing the Yamux library for session management.
Server-Side Configuration
In pkg/config/v1/server.go, TCPMux is enabled by default with TCPMux set to true:
// Server transport defaults to TCPMux enabled
// src: pkg/config/v1/server.go#L58-L64
c.TCPMux = util.EmptyOr(c.TCPMux, lo.ToPtr(true))
When TCPMuxHTTPConnectPort is configured, the server creates an HTTP CONNECT multiplexer listener in server/service.go:
// Create the http-connect multiplexer if needed
// src: server/service.go#L185-L199
if cfg.TCPMuxHTTPConnectPort > 0 {
address := net.JoinHostPort(cfg.ProxyBindAddr, strconv.Itoa(cfg.TCPMuxHTTPConnectPort))
l, err = net.Listen("tcp", address)
svr.rc.TCPMuxHTTPConnectMuxer, err = tcpmux.NewHTTPConnectTCPMuxer(l, cfg.TCPMuxPassthrough, vhostReadWriteTimeout)
}
Client-Side Connection Handling
On the client side, client/connector.go establishes a single TCP connection and wraps it in a Yamux session when tcpMux is enabled:
// Open the underlying connection and start a Yamux session
// src: client/connector.go#L15-L25
if !lo.FromPtr(c.cfg.Transport.TCPMux) { return nil }
conn, err := c.realConnect()
fmuxCfg := fmux.DefaultConfig()
fmuxCfg.KeepAliveInterval = time.Duration(c.cfg.Transport.TCPMuxKeepaliveInterval) * time.Second
session, err := fmux.Client(conn, fmuxCfg) // one Yamux session
c.muxSession = session
Each proxy connection request then opens a new logical stream within this session:
// Retrieve a stream from the Yamux session
// src: client/connector.go#L36-L42
stream, err := c.muxSession.OpenStream()
Stream Routing and HTTP CONNECT
The server routes multiplexed streams using server/group/tcpmux.go and server/proxy/tcpmux.go. For HTTP CONNECT proxying, pkg/util/tcpmux/httpconnect.go parses the CONNECT request and routes accordingly:
// Parse CONNECT request and produce a host-specific stream
// src: pkg/util/tcpmux/httpconnect.go#L49-L70
host, httpUser, httpPwd, err := muxer.readHTTPConnectRequest(rd)
Configuring TCPMux in frp
Server Configuration (frps)
Enable multiplexing and configure keep-alive intervals in frps.toml:
# frps.toml
[common]
# Enable multiplexing (default = true)
tcp_mux = true
tcp_mux_keepalive_interval = 30 # seconds
tcp_mux_http_connect_port = 7001 # port for HTTP CONNECT multiplexing
tcp_mux_passthrough = false # let frps handle CONNECT response
Client Configuration (frpc)
Configure the client to use the multiplexed connection:
# frpc.toml
[common]
server_addr = "your.frps.host"
server_port = 7000
tcp_mux = true # use one underlying connection
tcp_mux_keepalive_interval = 30 # keep-alive for the Yamux session
HTTP CONNECT Multiplexing
For HTTP CONNECT proxying, specify the multiplexer type in your proxy configuration:
[ssh]
type = "tcp"
local_port = 2222
remote_port = 22
multiplexer = "httpconnect" # tells frpc to use the HTTP CONNECT port
Key Source Files for frp TCP Stream Multiplexing
| Path | Role |
|---|---|
pkg/config/v1/server.go |
Transport configuration with default TCPMux = true |
client/connector.go |
Opens Yamux session and manages stream creation |
server/service.go |
Creates HTTP CONNECT multiplexer listener |
server/group/tcpmux.go |
Routes multiplexed streams to correct proxy listeners |
server/proxy/tcpmux.go |
Proxy factory for TCPMux type |
pkg/util/tcpmux/httpconnect.go |
Implements HTTP CONNECT multiplexing logic |
Summary
- frp TCP stream multiplexing collapses multiple logical proxy connections into a single physical TCP socket using the Yamux library.
- Eliminates per-connection overhead by removing TCP handshakes and TLS negotiations for each new proxy request.
- Reduces latency through persistent connections with configurable keep-alive intervals and shared congestion-control state.
- Simplifies infrastructure by aggregating traffic onto single ports and reducing kernel socket allocation.
- Maintains isolation between different proxies through logical stream routing while sharing the underlying transport.
Frequently Asked Questions
What is the difference between TCPMux and regular TCP proxying in frp?
Regular TCP proxying creates a new TCP connection for every proxy request, requiring a full TCP handshake and TLS negotiation each time. TCPMux maintains a single persistent TCP connection between frpc and frps, opening lightweight logical streams within that session for each new proxy request, which eliminates connection setup latency.
How does TCPMux affect latency compared to creating new connections?
TCPMux significantly reduces latency by removing the TCP three-way handshake and TLS handshake from the critical path of new proxy requests. Once the initial Yamux session is established, new streams start instantly without waiting for network round-trips, and shared congestion-control state ensures optimal throughput immediately rather than requiring slow-start ramp-up.
Can I use TCPMux with HTTP CONNECT proxying?
Yes, frp supports HTTP CONNECT multiplexing through the tcp_mux_http_connect_port configuration on the server and the multiplexer = "httpconnect" setting on the client. This allows the HTTP CONNECT protocol to benefit from the same connection reuse and reduced overhead as standard TCP multiplexing, with the server handling CONNECT request parsing in pkg/util/tcpmux/httpconnect.go.
What happens if the multiplexed connection drops?
If the underlying TCP connection carrying the Yamux session is interrupted, all logical streams within that session are terminated simultaneously. The frp client will automatically attempt to reconnect and establish a new Yamux session based on the configured keep-alive intervals and retry logic, but any in-flight requests on the dropped connection will need to be reestablished on the new session.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →