Test User 13fd446f40
ci / release-artifacts (push) Has been skipped
ci / test (push) Has been cancelled
fix: harden record completion path
2026-06-10 18:24:30 +08:00
2026-06-05 17:26:44 +08:00
2026-06-05 17:26:44 +08:00
2026-06-10 17:52:55 +08:00
2026-06-05 17:26:44 +08:00
2026-06-05 17:26:44 +08:00
2026-06-05 17:26:44 +08:00
2026-06-06 03:22:01 +08:00
2026-06-05 17:26:44 +08:00

NetStable

NetStable 是一个独立的 Go Web 测速项目,用于测试“打开网页的用户浏览器”到“部署服务器”的上传、下载和延迟。用户打开网页即可开始测试,页面会实时显示下载速度、上传速度、延迟、稳定评分和历史时序曲线。

功能

  • 同一时间只允许一个用户真正进行测速。
  • 其他用户发起请求时会进入 FIFO 队列,页面和 CLI 会显示当前排第几位,并在前面的用户完成后自动开始。
  • 启动时可设置程序理论最高带宽,例如 -bandwidth-limit-mbps 30 将测试流量限制到 30 Mbps。
  • 页面展示当前设置的理论最高限值。
  • 一次测试按阶段执行:先连续下载指定时长,再连续上传同样时长。页面固定提供 15s30s 两档,默认 30s
  • 手动停止、刷新页面或 CLI 中断时会取消当前会话并释放队列,后续用户会自动前移。
  • 下载/上传峰值使用连续样本的持续吞吐口径,避免单个短请求计时误差造成虚高峰值。
  • 保存每次测试的完整样本曲线、摘要、脱敏后的用户 IP、地区和运营商信息;ISP 缺失时显示“未知运营商”。
  • 所有历史测试用户数据通过网页和 /api/records 提供。
  • 历史时序图展示不同时段的平均下载速度变化。
  • 页面通过 SSE 心跳维持一条辅助长连接,用于显示连接状态和服务配置。
  • CLI 支持 HTTP 模式和 iperf3 模式;iperf3 模式由服务端在线随机生成一次性高端口,并复用同一个全局测速锁。
  • 页面可复制一键下载测试命令:用户服务器会从当前网站下载 CLI 二进制,然后立即发起测试。
  • 内置 GitHub 开源 ip2region_v4.xdb IPv4 数据库,优先离线解析地区和 ISP,避免外部 API 限流。
  • 静态页面嵌入二进制,部署时只需要上传一个可执行文件。

本地运行

go test ./...
go run ./cmd/netstable -listen 127.0.0.1:18080 -data data/records.jsonl

打开 http://127.0.0.1:18080/

构建

make test
make build

生成文件位于 dist/netstable

更新内置 IP 数据库:

make update-ip-db

Release 二进制

线上可以通过 Gitea Release 发布可直接下载的二进制压缩包,不建议把二进制提交到 Git 仓库。

仓库设置为 public 后,用户不需要登录即可下载 Release 附件。把下面命令中的 https://gitea.example.com/owner/netstable 替换成实际 public 仓库地址即可一键下载并启动:

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 附件:

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,然后上传上述附件。用户可以直接下载后运行:

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 部署

scp dist/netstable root@SERVER:/usr/local/bin/netstable
ssh root@SERVER 'mkdir -p /var/lib/netstable && chmod +x /usr/local/bin/netstable'

可直接启动:

/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

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 模式不依赖外部程序:

./netstable client -server http://103.46.93.38:18080 -duration 30

网页复制的一键命令会先下载 CLI 再测试,适合用户服务器没有 netstable 的情况:

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 会先请求服务端创建一次性会话,服务端随机开放一个临时高端口,测试结束后回写记录并释放锁:

./netstable client -mode iperf3 -server http://103.46.93.38:18080 -duration 30 -protocol tcp

UDP 示例:

./netstable client -mode iperf3 -server http://103.46.93.38:18080 -duration 30 -protocol udp -bandwidth-mbps 30

反向下载测试,即服务端发送到 CLI 客户端:

./netstable client -mode iperf3 -server http://103.46.93.38:18080 -duration 30 -reverse

输出 JSON

./netstable client -server http://103.46.93.38:18080 -duration 30 -json

常用参数:

  • -server: NetStable 服务端地址。
  • -mode: httpiperf3,默认 http
  • -duration: 每阶段时长,先下载同样秒数,再上传同样秒数。
  • -timeout: HTTP 请求超时,单位毫秒;iperf3 模式中也作为测试时长之外的额外等待时间,默认 3000
  • -target: 保存到记录里的目标标签,默认使用 -server 的 host。
  • -download-bytes: 每次下载请求大小,默认 4 MiB。
  • -upload-bytes: 每次上传请求大小,默认 2 MiB。
  • -protocol: iperf3 模式使用 tcpudp,默认 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.gznetstable-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-IPX-Real-IPX-Forwarded-For。直连公网时不要开启;放在可信反向代理后面时开启。
  • -bandwidth-limit-mbps: 程序理论最高带宽限制,单位 Mbps。示例:服务器 50 Mbps,希望测速程序最多使用 30 Mbps,则设置为 30;默认 0 表示不限速。
  • -iperf3-path: 服务端启动一次性 iperf3 会话时使用的可执行文件路径,默认 iperf3

Gitea

仓库可以直接推送到 Gitea。设置 remote 后执行:

git remote add origin <gitea-repo-url>
git push -u origin codex/go-network-stability-tester
S
Description
NetStable browser and CLI network speed/stability tester
Readme 4 MiB
Languages
Go 80%
JavaScript 13%
CSS 4.1%
HTML 2.1%
Makefile 0.8%