# NetStable NetStable 是一个独立的 Go Web 测速项目,用于测试“打开网页的用户浏览器”到“部署服务器”的上传、下载和延迟。用户打开网页即可开始测试,页面会实时显示下载速度、上传速度、延迟、稳定评分和历史时序曲线。 ## 功能 - 同一时间只允许一个用户真正进行测速。 - 其他用户发起请求时会进入 FIFO 队列,页面和 CLI 会显示当前排第几位,并在前面的用户完成后自动开始。 - 启动时可设置程序理论最高带宽,例如 `-bandwidth-limit-mbps 30` 将测试流量限制到 30 Mbps。 - 页面展示当前设置的理论最高限值。 - 一次测试按阶段执行:先连续下载指定时长,再连续上传同样时长。页面固定提供 `15s` 和 `30s` 两档,默认 `30s`。 - 手动停止、刷新页面或 CLI 中断时会取消当前会话并释放队列,后续用户会自动前移。 - 下载/上传峰值使用连续样本的持续吞吐口径,避免单个短请求计时误差造成虚高峰值。 - 保存每次测试的完整样本曲线、摘要、脱敏后的用户 IP、地区和运营商信息;ISP 缺失时显示“未知运营商”。 - 所有历史测试用户数据通过网页和 `/api/records` 提供。 - 历史时序图展示不同时段的平均下载速度变化。 - 页面通过 SSE 心跳维持一条辅助长连接,用于显示连接状态和服务配置。 - CLI 支持 HTTP 模式和 `iperf3` 模式;`iperf3` 模式由服务端在线随机生成一次性高端口,并复用同一个全局测速锁。 - 页面可复制一键下载测试命令:用户服务器会从当前网站下载 CLI 二进制,然后立即发起测试。 - 内置 GitHub 开源 `ip2region_v4.xdb` IPv4 数据库,优先离线解析地区和 ISP,避免外部 API 限流。 - 静态页面嵌入二进制,部署时只需要上传一个可执行文件。 ## 本地运行 ```bash go test ./... go run ./cmd/netstable -listen 127.0.0.1:18080 -data data/records.jsonl ``` 打开 `http://127.0.0.1:18080/`。 ## 构建 ```bash make test make build ``` 生成文件位于 `dist/netstable`。 更新内置 IP 数据库: ```bash make update-ip-db ``` ## Release 二进制 线上可以通过 Gitea Release 发布可直接下载的二进制压缩包,不建议把二进制提交到 Git 仓库。 仓库设置为 public 后,用户不需要登录即可下载 Release 附件。把下面命令中的 `https://gitea.example.com/owner/netstable` 替换成实际 public 仓库地址即可一键下载并启动: ```bash VERSION=v0.1.0 REPO=https://gitea.example.com/owner/netstable sh -c 'set -e; arch=$(uname -m); case "$arch" in x86_64) arch=amd64;; aarch64|arm64) arch=arm64;; *) echo "unsupported arch: $arch"; exit 1;; esac; tmp=$(mktemp -d); curl -fsSL "$REPO/releases/download/$VERSION/netstable-$VERSION-linux-$arch.tar.gz" | tar -xz -C "$tmp"; sudo install -m 0755 "$tmp/netstable" /usr/local/bin/netstable; sudo mkdir -p /var/lib/netstable; sudo /usr/local/bin/netstable -listen 0.0.0.0:18080 -data /var/lib/netstable/records.jsonl' ``` 生成 Linux release 附件: ```bash make release VERSION=v0.1.0 ``` 生成内容: - `dist/netstable-v0.1.0-linux-amd64.tar.gz` - `dist/netstable-v0.1.0-linux-arm64.tar.gz` - `dist/checksums.txt` 在 Gitea 的仓库页面创建 Release,标签填 `v0.1.0`,然后上传上述附件。用户可以直接下载后运行: ```bash tar -xzf netstable-v0.1.0-linux-amd64.tar.gz chmod +x netstable ./netstable -listen 0.0.0.0:18080 -data /var/lib/netstable/records.jsonl -downloads-dir /var/lib/netstable/downloads ``` ## Linux 部署 ```bash scp dist/netstable root@SERVER:/usr/local/bin/netstable ssh root@SERVER 'mkdir -p /var/lib/netstable && chmod +x /usr/local/bin/netstable' ``` 可直接启动: ```bash /usr/local/bin/netstable -listen 0.0.0.0:18080 -data /var/lib/netstable/records.jsonl -downloads-dir /var/lib/netstable/downloads ``` 也可以使用 `deploy/netstable.service`: ```bash scp deploy/netstable.service root@SERVER:/etc/systemd/system/netstable.service ssh root@SERVER 'systemctl daemon-reload && systemctl enable --now netstable' ``` ## CLI 测试 同一个二进制也可以作为客户端,在其他服务器上直接测试到部署节点的上传、下载和延迟。CLI 会复用 Web API,所以仍然遵守“同一时间只允许一个用户测速”的锁;如果前面有人正在测,CLI 会显示当前排队位置并持续等待,轮到自己后自动开始。 HTTP 模式不依赖外部程序: ```bash ./netstable client -server http://103.46.93.38:18080 -duration 30 ``` 网页复制的一键命令会先下载 CLI 再测试,适合用户服务器没有 `netstable` 的情况: ```bash arch=$(uname -m); case "$arch" in x86_64) arch=amd64;; aarch64|arm64) arch=arm64;; *) echo "unsupported arch: $arch"; exit 1;; esac; tmp=$(mktemp -d); curl -fsSL 'http://103.46.93.38:18080/downloads/netstable-linux-'"$arch"'.tar.gz' | tar -xz -C "$tmp" && chmod +x "$tmp/netstable" && "$tmp/netstable" client -server 'http://103.46.93.38:18080' -duration 30 ``` `iperf3` 模式需要客户端和服务端都安装 `iperf3`。CLI 会先请求服务端创建一次性会话,服务端随机开放一个临时高端口,测试结束后回写记录并释放锁: ```bash ./netstable client -mode iperf3 -server http://103.46.93.38:18080 -duration 30 -protocol tcp ``` UDP 示例: ```bash ./netstable client -mode iperf3 -server http://103.46.93.38:18080 -duration 30 -protocol udp -bandwidth-mbps 30 ``` 反向下载测试,即服务端发送到 CLI 客户端: ```bash ./netstable client -mode iperf3 -server http://103.46.93.38:18080 -duration 30 -reverse ``` 输出 JSON: ```bash ./netstable client -server http://103.46.93.38:18080 -duration 30 -json ``` 常用参数: - `-server`: NetStable 服务端地址。 - `-mode`: `http` 或 `iperf3`,默认 `http`。 - `-duration`: 每阶段时长,先下载同样秒数,再上传同样秒数。 - `-timeout`: HTTP 请求超时,单位毫秒;`iperf3` 模式中也作为测试时长之外的额外等待时间,默认 `3000`。 - `-target`: 保存到记录里的目标标签,默认使用 `-server` 的 host。 - `-download-bytes`: 每次下载请求大小,默认 4 MiB。 - `-upload-bytes`: 每次上传请求大小,默认 2 MiB。 - `-protocol`: `iperf3` 模式使用 `tcp` 或 `udp`,默认 `tcp`。 - `-reverse`: `iperf3` 反向模式,服务端向 CLI 客户端发送流量。 - `-bandwidth-mbps`: `iperf3` 目标带宽,默认跟随服务端 `-bandwidth-limit-mbps`。 - `-iperf3-path`: `iperf3` 可执行文件路径,默认 `iperf3`。 - `-quiet`: 不输出每个样本,只输出最终摘要。 ## 参数 - `-listen`: HTTP 监听地址,默认 `:8080`;部署示例使用高端口 `18080`。 - `-data`: JSONL 记录文件,默认 `data/records.jsonl`。 - `-static`: 可选静态资源目录;为空时使用嵌入资源。 - `-downloads-dir`: 可选二进制下载目录。目录中可放 `netstable-linux-amd64.tar.gz` 和 `netstable-linux-arm64.tar.gz`,通过 `/downloads/` 提供给网页一键命令下载。 - `-geo-base`: 在线 IP 归属地 API fallback 地址,默认 `https://ipapi.co`,并在默认源限流时自动尝试 `https://ipinfo.io`;内置 `ip2region` 会优先查询,设为空可关闭在线 fallback。 - `-geo-timeout`: IP 归属地查询超时,默认 `2s`。 - `-trust-proxy-headers`: 是否信任 `CF-Connecting-IP`、`X-Real-IP`、`X-Forwarded-For`。直连公网时不要开启;放在可信反向代理后面时开启。 - `-bandwidth-limit-mbps`: 程序理论最高带宽限制,单位 Mbps。示例:服务器 50 Mbps,希望测速程序最多使用 30 Mbps,则设置为 `30`;默认 `0` 表示不限速。 - `-iperf3-path`: 服务端启动一次性 `iperf3` 会话时使用的可执行文件路径,默认 `iperf3`。 ## Gitea 仓库可以直接推送到 Gitea。设置 remote 后执行: ```bash git remote add origin git push -u origin codex/go-network-stability-tester ```