118 lines
4.8 KiB
Markdown
118 lines
4.8 KiB
Markdown
# SpeedTest · 网速测试服务
|
||
|
||
基于 **Go + Gin + SQLite (GORM)** 的网页网速测试服务,支持 **延迟、下载、上传** 三项测试,
|
||
测速结果自动入库并生成 **排行榜**(下载榜 / 上传榜 / 延迟榜)。
|
||
|
||
- 线上地址: https://speedtest.lmve.net
|
||
- 代码仓库: https://git.lmve.net/dsh/speedtest
|
||
- 技术栈: Go 1.25 / Gin / GORM / SQLite (CGO) / TOML 配置 / systemd / Caddy
|
||
|
||
## 功能特性
|
||
|
||
- ⚡ **延迟测试**: 前端连续 10 次 ping,取中位数作为延迟、平均绝对偏差作为抖动
|
||
- ⬇️ **下载测试**: 自适应负载——单轮目标 ~2 秒、阶段最短 5 秒,负载从 1MB 起逐轮翻倍
|
||
(上限 400MB),实时仪表盘,取最优值;慢速连接 1-2 轮即结束,快速连接自动加大负载
|
||
- ⬆️ **上传测试**: 同样的自适应策略(1MB 起翻倍,上限 256MB),实时仪表盘,取最优值
|
||
- 🏆 **排行榜**: 下载 / 上传 / 延迟 三个榜单各取 Top 10,IP 自动打码(保留前 3 段)
|
||
- 🌐 **公网 IP 识别**: 服务器位于 NAT 后(公网访问经路由器转发,服务器只能看到内网 IP),
|
||
前端通过 ipinfo.io / ipify 探测真实公网出口 IP 用于展示与排行;内网 IP 在排行榜中标注
|
||
"内网 / NAT"
|
||
- 🔒 **Unix socket 监听**: 由 Caddy 反代对外提供 HTTPS,不暴露 TCP 端口
|
||
|
||
## 项目结构
|
||
|
||
```
|
||
speedtest/
|
||
├── main.go # 入口:加载配置 → 初始化数据库 → 启动 Web
|
||
├── install.sh # 一键安装/更新/卸载/管理脚本(systemd)
|
||
├── config/
|
||
│ ├── config.go # TOML 配置加载(缺失自动生成/补全)
|
||
│ └── defaults.go # 默认路径与默认值
|
||
├── internal/
|
||
│ ├── db/
|
||
│ │ ├── db.go # GORM 初始化 + 自动迁移
|
||
│ │ └── models.go # SpeedTestResult 数据模型
|
||
│ ├── store/
|
||
│ │ ├── stores.go # 数据访问层聚合
|
||
│ │ └── result_store.go # 测速结果增查(Top N / Count)
|
||
│ └── web/
|
||
│ ├── server.go # Gin 引擎 + 路由 + Unix socket/TCP 监听
|
||
│ ├── handlers/
|
||
│ │ └── speedtest.go # ping/download/upload/result/rankings
|
||
│ └── templates/
|
||
│ └── index.html # 前端单页(原生 JS,无外部依赖)
|
||
```
|
||
|
||
## 本地开发
|
||
|
||
```bash
|
||
# 编译(SQLite 依赖 CGO)
|
||
CGO_ENABLED=1 go build -ldflags="-s -w" -o speedtest .
|
||
|
||
# 本地运行(可用 SPEEDTEST_CONFIG 覆盖配置路径,见 test.toml 示例)
|
||
SPEEDTEST_CONFIG=./test.toml ./speedtest
|
||
```
|
||
|
||
## 部署(生产)
|
||
|
||
```bash
|
||
sudo ./install.sh install
|
||
```
|
||
|
||
脚本会自动完成:创建 `speedtest` 系统用户 → 创建目录 → 从 Gitea 拉取代码 →
|
||
编译(CGO_ENABLED=1)→ 部署二进制与模板 → 生成 systemd 服务 → 启动并设置开机自启。
|
||
|
||
| 项目 | 路径 |
|
||
| --- | --- |
|
||
| 程序目录 | `/opt/speedtest` |
|
||
| Unix socket | `/opt/speedtest/web.sock` |
|
||
| 配置文件 | `/etc/speedtest/speedtest.toml` |
|
||
| SQLite 数据库 | `/srv/speedtest/speedtest.db` |
|
||
| 日志 | `journalctl -u speedtest -f` |
|
||
|
||
### Caddy 反代配置
|
||
|
||
```caddy
|
||
speedtest.lmve.net {
|
||
reverse_proxy unix//opt/speedtest/web.sock {
|
||
header_up X-Real-IP {remote_host}
|
||
header_up Host {host}
|
||
}
|
||
}
|
||
```
|
||
|
||
## 配置文件
|
||
|
||
程序首次启动自动生成 `/etc/speedtest/speedtest.toml`(缺失项自动补全):
|
||
|
||
```toml
|
||
[database]
|
||
driver = "sqlite"
|
||
dsn = "/srv/speedtest/speedtest.db"
|
||
|
||
[web]
|
||
addr = "/opt/speedtest/web.sock" # 以 / 开头为 unix socket,否则为 TCP 端口
|
||
|
||
[speedtest]
|
||
max_download_bytes = 536870912 # 单次下载请求上限(默认 512 MB)
|
||
max_upload_bytes = 536870912 # 单次上传请求上限(默认 512 MB)
|
||
```
|
||
|
||
> 注:默认上限 512MB 服务于前端自适应测速(快速连接负载会翻倍增长);
|
||
> 旧版本配置中的 100MB 上限可手动调大,或删除配置行后重启让程序补全默认值。
|
||
|
||
## API
|
||
|
||
| 方法 | 路径 | 说明 |
|
||
| --- | --- | --- |
|
||
| GET | `/` | 测速页面 |
|
||
| GET | `/api/ping` | 延迟探测(返回 `{"pong":true,"ts":...,"client_ip":...}`) |
|
||
| GET | `/api/download?size=N` | 下载测速,流式返回 N 字节随机数据(默认 10MB,上限 512MB) |
|
||
| POST | `/api/upload` | 上传测速,接收请求体并返回 `received/elapsed_s/mbps` |
|
||
| POST | `/api/result` | 提交结果 `{latency_ms, jitter_ms, download_mbps, upload_mbps, client_ip?}` |
|
||
| GET | `/api/rankings` | 排行榜(`download/upload/latency` 三榜 + `total`,含 `is_private_ip` 标注) |
|
||
|
||
客户端真实 IP 优先取前端探测的公网出口 IP(`client_ip` 字段),
|
||
否则回退到 Caddy 注入的 `X-Real-IP` / `X-Forwarded-For`;
|
||
排行榜展示时对 IP 打码保护隐私,NAT/内网 IP 标注"内网 / NAT"。
|