{"id":43632679,"url":"https://github.com/lance0/xfr","last_synced_at":"2026-04-21T05:05:46.784Z","repository":{"id":335762527,"uuid":"1146944432","full_name":"lance0/xfr","owner":"lance0","description":"A modern iperf3 alternative with a live TUI, multi-client server, and QUIC support. Built in Rust.","archived":false,"fork":false,"pushed_at":"2026-04-16T00:36:39.000Z","size":1592,"stargazers_count":468,"open_issues_count":5,"forks_count":13,"subscribers_count":5,"default_branch":"master","last_synced_at":"2026-04-16T02:30:14.523Z","etag":null,"topics":["bandwidth","benchmark","cli","iperf","network","rust","tui"],"latest_commit_sha":null,"homepage":"","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/lance0.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":".github/FUNDING.yml","license":"LICENSE-APACHE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":"SECURITY.md","support":null,"governance":null,"roadmap":"ROADMAP.md","authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null},"funding":{"ko_fi":"lance0"}},"created_at":"2026-01-31T23:43:42.000Z","updated_at":"2026-04-16T00:36:42.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/lance0/xfr","commit_stats":null,"previous_names":["lance0/xfr"],"tags_count":19,"template":false,"template_full_name":null,"purl":"pkg:github/lance0/xfr","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lance0%2Fxfr","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lance0%2Fxfr/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lance0%2Fxfr/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lance0%2Fxfr/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/lance0","download_url":"https://codeload.github.com/lance0/xfr/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lance0%2Fxfr/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32076296,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-21T02:38:07.213Z","status":"ssl_error","status_checked_at":"2026-04-21T02:38:06.559Z","response_time":128,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["bandwidth","benchmark","cli","iperf","network","rust","tui"],"created_at":"2026-02-04T17:09:31.023Z","updated_at":"2026-04-21T05:05:46.777Z","avatar_url":"https://github.com/lance0.png","language":"Rust","readme":"# xfr\n\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"xfr-logo.png\" alt=\"xfr logo\" width=\"200\"\u003e\n\u003c/p\u003e\n\nA modern iperf3 alternative with a live TUI, multi-client server, MPTCP, and QUIC support. Built in Rust.\n\n[![Crates.io](https://img.shields.io/crates/v/xfr.svg)](https://crates.io/crates/xfr)\n[![CI](https://github.com/lance0/xfr/actions/workflows/ci.yml/badge.svg)](https://github.com/lance0/xfr/actions/workflows/ci.yml)\n[![License](https://img.shields.io/badge/license-MIT%2FApache--2.0-blue.svg)](LICENSE-MIT)\n[![Ko-fi](https://img.shields.io/badge/Ko--fi-tip-ff5e5b?logo=ko-fi)](https://ko-fi.com/lance0)\n\n## Quick Start\n\n```bash\n# Server\nxfr serve\n\n# Client (in another terminal or machine)\nxfr 192.168.1.1              # Basic TCP test\nxfr 192.168.1.1 -b 100M      # TCP at 100 Mbps\nxfr 192.168.1.1 -P 4         # 4 parallel streams\nxfr 192.168.1.1 -u -b 1G     # UDP at 1 Gbps\n```\n\nSee [Installation](#installation) below for setup instructions.\n\n## TUI Preview\n\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"xfr-ss.png\" alt=\"xfr TUI interface\" width=\"800\"\u003e\n\u003c/p\u003e\n\n## Features\n\n- **Live TUI** with real-time throughput graphs and per-stream stats\n- **Server dashboard** - `xfr serve --tui` for monitoring active tests\n- **Multi-client server** - handle multiple simultaneous tests\n- **TCP, UDP, QUIC, and MPTCP** with configurable bitrate pacing and parallel streams\n- **Firewall-friendly** - single-port TCP, QUIC multiplexing, and `--cport` for pinning UDP/QUIC/TCP data source ports\n- **Bidirectional testing** - measure upload and download simultaneously\n- **Multiple output formats** - plain text, JSON, JSON streaming, CSV\n- **Result comparison** - `xfr diff` to detect performance regressions\n- **LAN discovery** - find xfr servers with mDNS (`xfr discover`)\n- **Prometheus metrics** - export stats for monitoring dashboards\n- **Config file** - save defaults in `~/.config/xfr/config.toml`\n- **Environment variables** - `XFR_PORT`, `XFR_DURATION` overrides\n\n### vs iperf3\n\n| Feature | iperf3 | xfr |\n|---------|--------|-----|\n| Live TUI | No | Yes (client \u0026 server) |\n| Multi-client server | No | Yes |\n| MPTCP | No | Yes (auto on server, `--mptcp` on client, Linux 5.6+) |\n| Firewall-friendly | `--cport` (TCP/UDP) | Single-port TCP + `--cport` (UDP/QUIC/TCP data) |\n| Output formats | Text/JSON | Text/JSON/CSV |\n| Prometheus metrics | No | Yes (optional feature) |\n| Compare runs | No | `xfr diff` |\n| LAN discovery | No | `xfr discover` |\n| Config file | No | Yes |\n\n## Real-World Use Cases\n\n### VPN Tunnel Testing\nMeasure actual throughput through your VPN:\n```bash\n# On VPN server\nxfr serve\n\n# From client, through VPN\nxfr 10.8.0.1 -t 30s\n```\n\n### UDP Congestion Detection\nTest UDP at your expected rate to detect packet loss:\n```bash\nxfr \u003chost\u003e -u -b 500M -t 60s    # Watch for loss percentage in TUI\n```\n\n### Before/After Comparison\nQuantify the impact of network changes:\n```bash\nxfr \u003chost\u003e --json -o before.json\n# ... make changes ...\nxfr \u003chost\u003e --json -o after.json\nxfr diff before.json after.json --threshold 5\n```\n\n### Multi-Stream for Bonded Connections\nTest aggregate bandwidth across bonded/LACP interfaces:\n```bash\nxfr \u003chost\u003e -P 8 -t 30s          # 8 streams to utilize all links\n```\n\n### Prometheus Monitoring\nContinuous performance monitoring:\n```bash\nxfr serve --prometheus 9090 --push-gateway http://pushgateway:9091\n# Scrape metrics or view in Grafana\n```\n\n## Installation\n\n### From crates.io (Recommended)\n\nRequires [Rust 1.88+](https://www.rust-lang.org/tools/install):\n\n```bash\n# Install Rust (if not already installed)\ncurl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh\nsource ~/.cargo/env\n\n# Install xfr\ncargo install xfr\n```\n\n### Homebrew (macOS/Linux)\n\n```bash\nbrew install lance0/tap/xfr\n```\n\n### Pre-built Binaries\n\nDownload from [GitHub Releases](https://github.com/lance0/xfr/releases):\n\n| Platform | Target |\n|----------|--------|\n| Linux x86_64 | `xfr-x86_64-unknown-linux-musl.tar.gz` |\n| Linux ARM64 | `xfr-aarch64-unknown-linux-gnu.tar.gz` |\n| macOS Apple Silicon | `xfr-aarch64-apple-darwin.tar.gz` |\n| macOS Intel | Use `cargo install xfr` |\n| Android (Termux) | `xfr-aarch64-linux-android.tar.gz` |\n| Windows | Use WSL2 (native support is experimental) |\n\n```bash\n# Example: Linux x86_64\ncurl -LO https://github.com/lance0/xfr/releases/latest/download/xfr-x86_64-unknown-linux-musl.tar.gz\ntar xzf xfr-*.tar.gz \u0026\u0026 sudo mv xfr /usr/local/bin/\n```\n\n### eget\n\n```bash\neget lance0/xfr\n```\n\n### Arch Linux (AUR)\n\n```bash\nyay -S xfr-bin\n```\n\n### From Source\n\n```bash\ngit clone https://github.com/lance0/xfr\ncd xfr \u0026\u0026 cargo build --release\nsudo cp target/release/xfr /usr/local/bin/\n```\n\n### Quick Install Script\n\n\u003e **Note**: Review scripts before piping to sh. See the [install script](install.sh) source.\n\n```bash\ncurl -fsSL https://raw.githubusercontent.com/lance0/xfr/master/install.sh | sh\n```\n\n### Termux (Android)\n\nDownload the `aarch64-linux-android` binary from [releases](https://github.com/lance0/xfr/releases), or build from source:\n\n```bash\npkg install rust\ncargo install xfr\n```\n\n### Nix\n\n```bash\nnix run github:lance0/xfr          # Run without installing\nnix profile install github:lance0/xfr  # Install to profile\n```\n\nOr add to your flake inputs:\n\n```nix\ninputs.xfr.url = \"github:lance0/xfr\";\n```\n\nA dev shell is also available via `nix develop`.\n\n### NetBSD\n\nAvailable via [pkgsrc](https://pkgsrc.se/net/xfr):\n\n```bash\npkgin install xfr\n```\n\n### Optional Features\n\n| Feature | Default | Description |\n|---------|---------|-------------|\n| `discovery` | Yes | mDNS LAN discovery (`xfr discover`) |\n| `prometheus` | No | Prometheus metrics endpoint and Push Gateway support |\n\n```bash\ncargo install xfr --features prometheus    # Prometheus support\ncargo install xfr --all-features           # All features\n```\n\n### Shell Completions\n\n```bash\n# Bash\nxfr --completions bash \u003e ~/.local/share/bash-completion/completions/xfr\n\n# Zsh (add ~/.zfunc to fpath in .zshrc first)\nxfr --completions zsh \u003e ~/.zfunc/_xfr\n\n# Fish\nxfr --completions fish \u003e ~/.config/fish/completions/xfr.fish\n\n# PowerShell (add to $PROFILE)\nxfr --completions powershell \u003e\u003e $PROFILE\n\n# Elvish\nxfr --completions elvish \u003e ~/.elvish/lib/xfr.elv\n```\n\n## Usage\n\n### Server\n\n```bash\nxfr serve                    # Listen on port 5201\nxfr serve -p 9000            # Custom port\nxfr serve --tui              # Live dashboard showing active tests\nxfr serve --one-off          # Exit after one test\nxfr serve --max-duration 60s # Limit test duration\nxfr serve --push-gateway http://pushgateway:9091  # Push metrics on test complete\nxfr serve --psk mysecret     # Require PSK authentication\nxfr serve --rate-limit 2     # Max 2 concurrent tests per IP\nxfr serve --allow 192.168.0.0/16 --deny 0.0.0.0/0  # IP ACL\n```\n\n### Client\n\n```bash\nxfr 192.168.1.1              # TCP test, 10s, single stream\nxfr 192.168.1.1 -t 30s       # 30 second test\nxfr 192.168.1.1 -P 4         # 4 parallel streams\nxfr 192.168.1.1 -R           # Reverse (download test)\nxfr 192.168.1.1 --bidir      # Bidirectional\nxfr 192.168.1.1 -6           # Force IPv6 only\nxfr ::1 -6                   # IPv6 localhost\n```\n\n### UDP Mode\n\n```bash\nxfr 192.168.1.1 -u           # UDP mode\nxfr 192.168.1.1 -u -b 1G     # UDP at 1 Gbps\nxfr 192.168.1.1 -u -b 100M   # UDP at 100 Mbps\n```\n\n### QUIC Mode\n\n```bash\nxfr 192.168.1.1 --quic       # QUIC transport (encrypted)\nxfr 192.168.1.1 --quic -P 4  # QUIC with 4 parallel streams\nxfr 192.168.1.1 --quic -R    # QUIC download test\n```\n\nQUIC provides built-in TLS 1.3 encryption with stream multiplexing over a single connection.\n\n**Security Note:** QUIC encrypts traffic but does not verify server identity by default. For authenticated connections, use `--psk` on both client and server to prevent MITM attacks.\n\n### MPTCP Mode\n\n```bash\nxfr 192.168.1.1 --mptcp       # MPTCP (Multi-Path TCP, Linux 5.6+)\nxfr 192.168.1.1 --mptcp -P 4  # MPTCP with 4 parallel streams\nxfr 192.168.1.1 --mptcp -R    # MPTCP download test\n```\n\nMPTCP enables a single connection to use multiple network paths simultaneously (e.g., WiFi + Ethernet). The server automatically creates MPTCP listeners — no flag needed on the server side. All TCP features (nodelay, congestion control, window size, bidir, multi-stream) work transparently with MPTCP.\n\n### Output Formats\n\n```bash\nxfr \u003chost\u003e --json              # JSON summary\nxfr \u003chost\u003e --json-stream       # JSON per interval (for scripting)\nxfr \u003chost\u003e --csv               # CSV output\nxfr \u003chost\u003e -q                  # Quiet mode (summary only)\nxfr \u003chost\u003e -o results.json     # Save to file\nxfr \u003chost\u003e --no-tui            # Plain text, no TUI\nxfr \u003chost\u003e --timestamp-format iso8601  # ISO 8601 timestamps\n```\n\n**Note:** Log messages go to stderr, allowing clean JSON/CSV piping: `xfr \u003chost\u003e --json 2\u003e/dev/null`\n\n### Interval Control\n\n```bash\nxfr \u003chost\u003e -i 2                # Report every 2 seconds\nxfr \u003chost\u003e --omit 3            # Skip first 3s of intervals (TCP ramp-up)\n```\n\n### Compare Results\n\n```bash\nxfr diff baseline.json current.json\nxfr diff baseline.json current.json --threshold 5\n```\n\n### Discovery\n\n```bash\nxfr discover                 # Find xfr servers on LAN\nxfr discover --timeout 10s   # Extended search\n```\n\n## Keybindings (Client TUI)\n\n| Key | Action |\n|-----|--------|\n| `q` | Quit (cancels test) |\n| `p` | Pause/Resume display |\n| `s` | Settings modal |\n| `t` | Cycle color theme |\n| `d` | Toggle per-stream view |\n| `?` / `F1` | Help |\n| `j` | Print JSON result |\n| `u` | Dismiss update notification |\n\n## Keybindings (Server TUI)\n\n| Key | Action |\n|-----|--------|\n| `q` | Quit server |\n| `?` / `F1` | Help |\n| `Esc` | Close help |\n\n## Themes\n\nxfr includes 11 built-in color themes. Select with `--theme` or press `t` during a test:\n\n```bash\nxfr \u003chost\u003e --theme dracula     # Dark purple theme\nxfr \u003chost\u003e --theme matrix      # Green on black hacker style\nxfr \u003chost\u003e --theme catppuccin  # Soothing pastels\nxfr \u003chost\u003e --theme nord        # Arctic blue tones\n```\n\nAvailable themes: `default`, `kawaii`, `cyber`, `dracula`, `monochrome`, `matrix`, `nord`, `gruvbox`, `catppuccin`, `tokyo_night`, `solarized`\n\nYour theme preference is auto-saved to `~/.config/xfr/prefs.toml`.\n\n## Configuration\n\nxfr reads defaults from:\n- **Linux/macOS:** `~/.config/xfr/config.toml`\n- **Windows:** `%APPDATA%\\xfr\\config.toml`\n\n```toml\n[client]\nduration_secs = 10\nparallel_streams = 1\ntcp_nodelay = false\nwindow_size = \"1M\"           # TCP window size (e.g., \"512K\", \"2M\")\njson_output = false\nno_tui = false\ntheme = \"default\"            # or dracula, catppuccin, nord, matrix, etc.\ntimestamp_format = \"relative\" # or \"iso8601\", \"unix\"\naddress_family = \"dual\"      # \"ipv4\", \"ipv6\", or \"dual\"\nomit_secs = 0                # omit first N seconds (TCP ramp-up)\npsk = \"my-secret-key\"\nlog_file = \"~/.config/xfr/xfr.log\"\nlog_level = \"info\"\n\n[server]\nport = 5201\none_off = false\nno_mdns = false\naddress_family = \"dual\"      # \"ipv4\", \"ipv6\", or \"dual\"\npsk = \"my-secret-key\"\nrate_limit = 5\nrate_limit_window = 60\nallow = [\"192.168.0.0/16\", \"10.0.0.0/8\"]\ndeny = []\nacl_file = \"/path/to/acl.txt\"\npush_gateway = \"http://pushgateway:9091\"\nlog_file = \"~/.config/xfr/xfr-server.log\"\nlog_level = \"info\"\n```\n\n`[client] omit_secs` sets the default for `--omit`. An explicit CLI `--omit` value, including `--omit 0`, takes precedence over the config file.\n\nEnvironment variables override config file:\n\n```bash\nexport XFR_PORT=9000\nexport XFR_DURATION=30s\n```\n\n## Prometheus Metrics\n\nEnable with `--features prometheus`:\n\n```bash\nxfr serve --prometheus 9090\n```\n\nMetrics available at `http://localhost:9090/metrics`:\n\n- `xfr_bytes_total` - Total bytes transferred\n- `xfr_throughput_mbps` - Current throughput\n- `xfr_active_tests` - Number of active tests\n- `xfr_retransmits_total` - TCP retransmissions\n\nSee `examples/grafana-dashboard.json` for a sample Grafana dashboard.\n\n## CLI Reference\n\n| Flag | Short | Default | Description |\n|------|-------|---------|-------------|\n| `--port` | `-p` | 5201 | Server/client port |\n| `--time` | `-t` | 10s | Test duration (use 0 for infinite) |\n| `--udp` | `-u` | false | UDP mode |\n| `--quic` | `-Q` | false | QUIC mode (encrypted, multiplexed streams) |\n| `--bitrate` | `-b` | unlimited | Target bitrate for TCP and UDP (e.g., 1G, 100M). 0 = unlimited. Global across all streams |\n| `--parallel` | `-P` | 1 | Parallel streams |\n| `--reverse` | `-R` | false | Reverse direction (download) |\n| `--bidir` | | false | Bidirectional test |\n| `--ipv4` | `-4` | false | Force IPv4 only |\n| `--ipv6` | `-6` | false | Force IPv6 only |\n| `--bind` | | none | Local address to bind (e.g., 192.168.1.100) |\n| `--cport` | | none | Client source port for firewall traversal (UDP/QUIC/TCP data streams) |\n| `--dscp` | | none | DSCP/TOS marking for TCP/UDP QoS testing (0-255 or name: EF, AF11, CS1, etc.) |\n| `--mptcp` | | false | MPTCP mode (client-only, Linux 5.6+; server auto-enables) |\n| `--random` | | true | Use random payload data for client-sent TCP/UDP traffic (default) |\n| `--zeros` | | false | Use zero-filled payload data (client-sent traffic only) |\n| `--json` | | false | JSON output |\n| `--json-stream` | | false | JSON per interval |\n| `--csv` | | false | CSV output |\n| `--quiet` | `-q` | false | Summary only |\n| `--interval` | `-i` | 1.0 | Report interval (seconds) |\n| `--omit` | | 0 | Omit first N seconds |\n| `--output` | `-o` | stdout | Output file |\n| `--no-tui` | | false | Disable TUI |\n| `--theme` | | default | Color theme (dracula, nord, matrix, etc.) |\n| `--tcp-nodelay` | | false | Disable Nagle algorithm |\n| `--window` | `-w` | OS default | TCP window size; when unset, kernel autotunes |\n| `--congestion` | | OS default | TCP congestion control algorithm (e.g. cubic, bbr, reno) |\n| `--timestamp-format` | | relative | Timestamp format (relative, iso8601, unix) |\n| `--log-file` | | none | Log file path (e.g., ~/.config/xfr/xfr.log) |\n| `--log-level` | | info | Log level (error, warn, info, debug, trace) |\n| `--push-gateway` | | none | Prometheus Push Gateway URL (server) |\n| `--prometheus` | | none | Prometheus metrics port (server, requires feature) |\n| `--psk` | | none | Pre-shared key for authentication |\n| `--psk-file` | | none | Read PSK from file |\n| `--rate-limit` | | none | Max concurrent tests per IP (server) |\n| `--rate-limit-window` | | 60s | Rate limit time window (server) |\n| `--completions` | | none | Generate shell completions (bash, zsh, fish, powershell, elvish) |\n| `--allow` | | none | Allow IP/subnet, repeatable (server) |\n| `--deny` | | none | Deny IP/subnet, repeatable (server) |\n| `--acl-file` | | none | ACL rules file (server) |\n| `--max-duration` | | none | Maximum test duration, server-side limit (server) |\n| `--tui` | | false | Enable live dashboard (server) |\n| `--one-off` | | false | Exit after one test (server, works with TCP and QUIC) |\n| `--no-mdns` | | false | Disable mDNS service registration (server) |\n\nTCP and UDP tests use random payloads by default to avoid inflated results on WAN-optimized or compressing paths. `--random` and `--zeros` control client-sent traffic. Server-sent TCP/UDP traffic also defaults to random, but payload mode is not negotiated over the wire.\n\n`--dscp` applies to TCP and UDP client sockets. QUIC ignores it because the underlying socket is managed by Quinn, and non-Unix platforms currently warn instead of applying socket marking.\n\n## Security Considerations\n\n### Transport Encryption\n\n| Mode | Encryption | Certificate Verification |\n|------|------------|-------------------------|\n| TCP | None | N/A |\n| UDP | None | N/A |\n| QUIC | TLS 1.3 | Disabled by default |\n\n**QUIC mode** (`-Q/--quic`) provides TLS 1.3 encryption but does not verify server certificates, making it vulnerable to MITM attacks without additional authentication. **Always use `--psk` with QUIC on untrusted networks.** Alternatively, use a VPN or SSH tunnel.\n\n### Authentication\n\nPSK authentication (`--psk`) verifies client identity but does not encrypt TCP/UDP traffic. For encrypted + authenticated connections, use QUIC with PSK:\n\n```bash\n# Server\nxfr serve --psk \"secretkey\"\n\n# Client (encrypted + authenticated)\nxfr \u003chost\u003e -Q --psk \"secretkey\"\n```\n\n### Network Considerations\n\n- **Single-port TCP**: TCP uses single-port mode by default -- control and data connections share port 5201. Data connections are validated against the control connection's IP address, preventing unauthorized access.\n- **UDP on untrusted networks**: UDP mode may be susceptible to reflection attacks from spoofed source addresses. Use TCP or QUIC on public networks.\n- **Rate limiting**: Use `--rate-limit` on public servers to prevent abuse.\n- **ACLs**: Use `--allow`/`--deny` to restrict client access.\n\n### DoS Protections\n\n- **Slow-loris resistance**: New connections must send their first message within 5 seconds, preventing slow-loris attacks from blocking the accept loop.\n- **DataHello flood protection**: DataHello messages for unknown test IDs are rejected immediately without allocating resources.\n- **Bounded reads**: All control messages are limited to 8KB, preventing memory exhaustion from oversized messages.\n- **Capability negotiation**: Client and server exchange capabilities during the Hello handshake (protocol version 1.1), enabling safe feature evolution.\n- **Concurrent connection limits**: Server limits concurrent handlers (default 100) to prevent connection floods.\n\n### Server Resource Usage\n\nEach TCP stream allocates a 128 KB application read/write buffer. Kernel socket buffers are managed by TCP autotuning unless the client passes `-w`/`--window`, in which case the requested size is applied via `SO_SNDBUF`/`SO_RCVBUF` on both ends. Memory usage scales with concurrent clients:\n\n| Streams per client | App buffer per client | 10 clients (app buffers) |\n|-------------------|-----------------------|--------------------------|\n| 1 (`-P 1`) | 128 KB | 1.3 MB |\n| 8 (`-P 8`) | 1 MB | 10 MB |\n| 128 (`-P 128`) | 16 MB | 160 MB |\n\nOn top of that, the kernel holds autotuned socket buffers (typically a few hundred KB per stream, capped by `net.ipv4.tcp_rmem[2]`/`tcp_wmem[2]`). When a client passes `-w N`, add roughly `N` bytes per stream on each side. The server limits concurrent handlers (default 100) to prevent resource exhaustion. Use `--rate-limit` to restrict tests per IP.\n\n## Platform Support\n\n| Platform | Status |\n|----------|--------|\n| Linux x86_64/ARM64 | Full support, pre-built binaries |\n| macOS Apple Silicon | Full support, pre-built binaries |\n| macOS Intel | Full support, build from crate: `cargo install xfr` |\n| Android (Termux) | Full support, pre-built binaries |\n| NetBSD | Full support, via pkgsrc: `pkgin install xfr` |\n| Windows | Experimental (WSL2 recommended). Native builds work but lack TCP_INFO metrics. |\n\n## Troubleshooting\n\n### Permission denied on port 5201\n\nUse a port above 1024 or run with elevated privileges:\n\n```bash\nxfr serve -p 9000\n```\n\n### Connection refused\n\nEnsure the server is running and the port is not blocked by a firewall. TCP only requires port 5201 (or your custom port) to be open on the server -- no additional server-side data ports are needed. For strict egress policies or ECMP testing, use `--cport` to pin client source ports for TCP or UDP, or use QUIC which multiplexes on a single port.\n\n### Low throughput\n\n- Try multiple parallel streams: `-P 4`\n- Disable Nagle's algorithm: `--tcp-nodelay`\n- Increase TCP window size: `--window 4M`\n\n### UDP packet loss\n\n- Reduce bitrate: `-b 500M`\n- Check for network congestion or firewall issues\n\n## Documentation\n\n- [Comparison with iperf3](docs/COMPARISON.md) - Feature matrix and migration guide\n- [Scripting \u0026 CI/CD](docs/SCRIPTING.md) - Automation, Docker, Prometheus\n- [Features Reference](docs/FEATURES.md) - Detailed feature documentation\n- [Architecture](docs/ARCHITECTURE.md) - For contributors\n- [Changelog](CHANGELOG.md) - Release history\n- [Known Issues](KNOWN_ISSUES.md) - Edge cases and limitations\n- [Roadmap](ROADMAP.md) - Planned features\n- [Contributing](CONTRIBUTING.md) - Development guidelines\n\n## See Also\n\n- [Terminal Trove](https://terminaltrove.com/xfr/) - xfr listing and discovery\n- [AUR](https://aur.archlinux.org/packages/xfr-bin) - Arch Linux package (community-maintained)\n- [pkgsrc](https://pkgsrc.se/net/xfr) - NetBSD package (community-maintained)\n\n## Acknowledgments\n\nSpecial thanks to [Matthieu Baerts (matttbe)](https://github.com/matttbe), Linux kernel MPTCP co-maintainer, for extensive testing, detailed bug reports with packet traces, and feature suggestions including MPTCP support, kernel TCP pacing, zero-copy IO, and high stream-count hardening. xfr is significantly better because of his contributions.\n\n## License\n\nLicensed under either of [Apache License, Version 2.0](LICENSE-APACHE) or [MIT license](LICENSE-MIT) at your option.\n","funding_links":["https://ko-fi.com/lance0"],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flance0%2Fxfr","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Flance0%2Fxfr","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flance0%2Fxfr/lists"}