Skip to content

AliRezaBeigy/TransportProxy

Repository files navigation

Transport Proxy

Compare KCP & QUIC transports in Rust — benchmarks & proxy harness

Rust License

This project compares transport implementations in Rust: KCP (kcp-tokio, kcp-deepseek, kcprs, ys-kcp, kcp-sys) and QUIC (quinn). It includes a TCP-over-KCP proxy and echo/load-test tools; benchmarks measure throughput, latency, and concurrency across all implementations (see tables below).

Benchmarks

cargo bench
Group Description
kcp_tokio_* Real UDP (kcp-tokio), 64B–8KB, latency, concurrent
quinn_* QUIC over UDP with TLS (quinn)
kcp_deepseek_* UDP localhost (deepseeksss/kcp + bench bridge)
kcprs_* UDP localhost (kcprs), pure Rust + bench bridge
ys_kcp_* UDP localhost (ys-kcp fork with send fix); optional, nightly
slipstream_* QUIC over UDP (slipstream-picoquic); optional
kcp_sys_* UDP localhost (kcp-sys), endpoints wired through tokio UDP; optional, libclang (throughput + latency)

Refresh results: .\scripts\bench_to_readme.ps1 (default = all). -Lib default | ys_kcp | kcp_sys for one; -SkipRun = no run, just update README from existing target\criterion.

Benchmark results

Generated by scripts/bench_to_readme.ps1. Run cargo bench then this script to refresh.

Last updated: 2026-03-01 09:09 Hardware: 13th Gen Intel(R) Core(TM) i7-13700K (16 cores / 24 logical), 63.75 GB RAM, Microsoft Windows 11 Pro

Comparison: time per roundtrip (lower is better)

Payload kcp_tokio (UDP) quinn (QUIC) slipstream_picoquic kcp_deepseek kcprs ys_kcp kcp_sys
64 B 148.62 µs 81.95 µs 89.11 µs 1.12 ms 1.14 ms 1.14 ms 8.50 ms
256 B 158.25 µs 85.10 µs 79.16 µs 1.09 ms 1.12 ms 1.12 ms 18.93 ms
1 KiB 153.99 µs 86.44 µs 85.81 µs 1.10 ms 1.12 ms 1.13 ms 10.29 ms
4 KiB 262.05 µs 120.65 µs 203.13 µs 3.26 ms 2.13 ms 4.12 ms
8 KiB 420.61 µs 154.83 µs 290.72 µs 1.74 ms 2.51 ms 1.15 ms

¹ kcprs 4 KiB/8 KiB skipped (see throughput notes). kcp_deepseek/kcprs/ys_kcp times include ~1 ms synchronous polling floor; see throughput methodology notes.

Comparison: throughput (higher is better)

Payload kcp_tokio (UDP) quinn (QUIC) slipstream_picoquic kcp_deepseek kcprs ys_kcp kcp_sys
64 B 420.53 KiB/s 762.64 KiB/s 701.41 KiB/s 55.74 KiB/s 54.61 KiB/s 55.04 KiB/s 7.35 KiB/s²
256 B 1.54 MiB/s 2.87 MiB/s 3.08 MiB/s 230.41 KiB/s 223.89 KiB/s 222.43 KiB/s 13.21 KiB/s²
1 KiB 6.34 MiB/s 11.30 MiB/s 11.38 MiB/s 910.55 KiB/s 895.08 KiB/s 888.82 KiB/s 97.16 KiB/s²
4 KiB 14.91 MiB/s 32.38 MiB/s 19.23 MiB/s 1.20 MiB/s 1.83 MiB/s 969.74 KiB/s²
8 KiB 18.57 MiB/s 50.46 MiB/s 26.87 MiB/s 4.49 MiB/s 3.11 MiB/s 6.77 MiB/s²

Methodology notes:

  • kcp_tokio and quinn reuse a single connection (and stream, for quinn) across all hot-path iterations per payload size — only the per-roundtrip cost is measured. quinn uses length-prefix framing to keep the QUIC stream open without calling finish(), matching kcp_tokio's stream-reuse pattern.
  • kcp_deepseek, kcprs, and ys_kcp use a synchronous polling harness: both client and server run in the same thread and exchange UDP datagrams via a busy-wait loop (200 µs sleep per iteration). The ~1 ms floor in their results reflects this polling overhead, not raw protocol throughput. kcp_tokio and quinn use a real async I/O server with OS-scheduled I/O.
  • ¹ kcprs 4 KiB/8 KiB skipped: kcprs-0.5.0 panics on multi-segment payloads due to an out-of-bounds bug in parse_ack() (snd_buf.remove(i) inside a non-breaking loop over snd_buf.len()).
  • ² kcp_sys throughput reinitializes client and server per iteration (the kcp-sys server exits after the first stream closes, causing subsequent accept() calls to hang). These numbers measure connect+roundtrip cost, not sustained throughput — treat them as equivalent to the latency bench.

Comparison: success rate (higher is better)

Payload kcp_tokio (UDP) quinn (QUIC) slipstream_picoquic kcp_deepseek kcprs ys_kcp kcp_sys
64 B 100% 100% 100% 100% 100% 100% 100%
256 B 100% 100% 100% 100% 100% 100% 100%
1 KiB 100% 100% 100% 100% 100% 100% 100%
4 KiB 100% 100% 100% 100% - 100% 100%
8 KiB 100% 100% 100% 100% - 100% 100%

Comparison: latency (64 B RTT, lower is better)

Benchmark kcp_tokio (UDP) quinn (QUIC) slipstream_picoquic kcp_deepseek kcprs ys_kcp kcp_sys
64 B RTT 3.13 ms 552.31 µs 1.19 ms 1.11 ms 1.16 ms 1.18 ms 9.14 ms
Success rate 99.9% 100% 100% 100% 100% 100% 99.9%

Usage

The proxy server, proxy client, and load_test binaries support a selectable transport: kcp-tokio (KCP over UDP) or quinn (QUIC over UDP). Use --transport to choose; server and client must use the same transport.

Transport Description
kcp-tokio KCP over UDP (default)
quinn QUIC over UDP with TLS (self-signed cert; client accepts any cert for local use)

Echo server (no upstream)

# Server: KCP echo on 0.0.0.0:12345 (default transport)
cargo run --bin proxy_server -- --listen 0.0.0.0:12345

# Server: QUIC echo on 0.0.0.0:12345
cargo run --bin proxy_server -- --transport quinn --listen 0.0.0.0:12345

Proxy server (forward to upstream TCP)

# Server: KCP on 0.0.0.0:12345 -> TCP 127.0.0.1:8080
cargo run --bin proxy_server -- --listen 0.0.0.0:12345 --upstream 127.0.0.1:8080

# Server: QUIC on 0.0.0.0:12345 -> TCP 127.0.0.1:8080
cargo run --bin proxy_server -- --transport quinn --listen 0.0.0.0:12345 --upstream 127.0.0.1:8080

Proxy client

# Client: TCP 127.0.0.1:9000 -> KCP proxy at 127.0.0.1:12345
cargo run --bin proxy_client -- --listen 127.0.0.1:9000 --proxy 127.0.0.1:12345

# Client: TCP 127.0.0.1:9000 -> QUIC proxy at 127.0.0.1:12345
cargo run --bin proxy_client -- --transport quinn --listen 127.0.0.1:9000 --proxy 127.0.0.1:12345

Then connect to 127.0.0.1:9000 with any TCP client; traffic is tunneled over the selected transport to the server.

Load test

Start the echo server first (with the same transport you will use for the load test), then:

# KCP: 10 connections, 100 messages each, 512-byte messages
cargo run --release --bin load_test -- --server 127.0.0.1:12345 --connections 10 --messages 100 --message-size 512

# QUIC load test (server must be started with --transport quinn)
cargo run --release --bin load_test -- --transport quinn --server 127.0.0.1:12345 --connections 10 --messages 100

# Run for 5 seconds
cargo run --release --bin load_test -- --server 127.0.0.1:12345 --connections 10 --duration-secs 5

Tests

cargo test

Runs unit tests and integration tests (echo: single/multiple/large message over KCP).

Build & Development

See DEVELOPMENT.md for build and development (format, clippy).

Dependencies

  • kcp-tokio 0.4 — async KCP on Tokio (selectable: --transport kcp-tokio)
  • quinn 0.11 — QUIC over UDP (selectable: --transport quinn; server/client/load_test)
  • kcp (git) — core KCP protocol for benchmarks
  • kcprs 0.5 — pure Rust KCP for benchmarks
  • ys-kcp (fork of ys4e/ys-kcp, includes fix for segment payload in send()), kcp-sys — optional (benchmarks only): --features ys-kcp (nightly) or --features kcp-sys (libclang)
  • tokio, tracing, anyhow, clap, rcgen, rustls

License

MIT


Made with ❤️

About

Compare KCP & QUIC transports in Rust — TCP-over-KCP proxy, echo/load-test tools, and throughput/latency benchmarks.

Topics

Resources

Stars

Watchers

Forks

Contributors