[点晴永久免费OA]STUN Max:一个用 Go 编写的 P2P 隧道工具
STUN Max:我用 Go 写了一个 P2P 隧道工具
从 STUN 打洞到 gVisor ,一个人走完了整条路
2026-04-06 | 开发者视角

“我只是想把家里的 NAS 端口暴露出来,结果走上了一条从 STUN 打洞、X25519 加密、gVisor 协议栈到 GioUI 跨平台 GUI 的不归路。这篇文章记录了我如何用 16000 行 Go 代码,写出了一个真正能用的 P2P 隧道工具。”
同类工具对比:为什么还要造轮子?
在动手之前,我认真评估了市面上的主流方案。每个工具都有它的优势,但没有一个完美契合我的场景——轻量、P2P 优先、零配置、自带 GUI。
工具 | 协议 | P2P | GUI | 复杂度 |
frp | TCP/KCP | ✖ 中转 | ✖ CLI | 低 |
ngrok | HTTP/TCP | ✖ 云代理 | ✖ Web | 低 |
WireGuard | UDP | ✔ 点对点 | ✖ CLI | 中 |
ZeroTier | UDP | ✔ 组网 | ✔ 简单 | 高 |
STUN Max | UDP+WS | ✔ P2P 优先 | ✔ 原生 GUI | 低 |
所以我决定自己动手。目标很简单:P2P 优先、连不上就自动回退到服务器中转、所有平台都能用。
系统架构:信令 + 打洞 + 隧道

▲ 图 1:STUN Max 系统架构
整个系统分三层:Signal Server 负责房间管理和转发信令,客户端通过 WebSocket 加入房间后发现对端。接着用 STUN 探测 NAT 类型,尝试 UDP 打洞建立 P2P 直连。如果打洞失败,自动回退到服务器 Relay 中转。
这套设计的好处是用户无感知——不管是 P2P 还是 Relay,上层的端口转发、文件传输、VPN 都透明工作。
八大功能模块一览
Peers 节点发现
实时显示房间内所有对端的在线状态、NAT 类型、连接方式(P2P/Relay)和延迟数据。支持多节点同时在线。

▲ Peers 节点发现
Forwards 端口转发
把远端服务的端口映射到本地。支持同时转发多个端口,一键启停。

▲ Forwards 端口转发
Files 文件传输
基于 gVisor TCP 流式传输,P2P 优先。支持拖拽文件、自动接受、进度显示。

▲ Files 文件传输
VPN 虚拟网络
通过 gVisor 用户态协议栈实现 TUN 设备。支持多节点同时 VPN,路由自动追加。

▲ VPN 虚拟网络
Speed Test 测速
内置对等测速功能,直接测试两端之间的实际带宽和延迟。

▲ Speed Test 测速
Tools 工具箱
集成 NAT 类型检测、网络诊断等实用工具。

▲ Tools 工具箱
Settings 设置
服务器地址、房间配置、加密参数、界面主题等全局设置。

▲ Settings 设置
Logs 日志
实时滚动日志,方便调试和问题定位。

▲ Logs 日志
Android 5 大坑:踩过才知道的教训
说实话,Android 适配花的时间比核心功能还多。以下是我踩过的 5 个最痛的坑:
坑 1:EGL 崩溃 — GioUI 的 Android 噪梦
GioUI 在某些低端 Android 设备上会触发 EGL 初始化崩溃。根因是 GPU 驱动不支持某些 OpenGL ES 扩展。解决方案是回退到软件渲染:
● ● ● Go |
// 检测 EGL 能力,必要时回退到 Software Renderer |
坑 2:字体空白 — 中文全没了
GioUI 默认的字体回退链在部分 Android 版本上找不到中文字体,导致所有中文显示为空白。解决方案是内嵌 HarmonyOS Sans 字体文件并在初始化时强制加载。
坑 3:VPN 权限 — Activity vs Application Context
Android VPN 服务需要通过 VpnService.prepare() 获取权限,但这个方法必须从 Activity Context 调用。如果用 Application Context,会静默失败。这个 Bug 排查了整整一天。
● ● ● Go |
// 正确:使用 Activity Context |
坑 4:Multidex FindClass 失败
Go 生成的 Android 库文件较大,触发了 Multidex 限制。在 Android 5.0 以下版本,必须显式启用 Multidex,否则启动时直接 ClassNotFoundException。
坑 5:APK 构建流水线
Go + Android NDK 交叉编译的工具链配置非常繁琐。最终用 GitHub Actions 搞定了自动化构建,支持 arm64 和 arm32 双架构。整个流程从代码推送到 APK 产出大约 8 分钟。
P2P 核心技术:打洞 + 加密 + 隧道
全链路加密基于 X25519 ECDH + AES-256-GCM。每次建立连接时,双方生成临时密钥对,通过 ECDH 协商出共享密钥,然后用 AES-256-GCM 加密所有隧道数据。即使中转服务器也无法解密内容。
隧道协议设计得很简单:open_tunnel → tunnel_opened → tunnel_data(base64)→ close_tunnel。所有消息都封装在 relay_data 信封里,服务器只负责转发,不解析内容。
gVisor 用户态协议栈是整个 VPN 的基础。它让我不需要系统级权限就能处理 TCP/IP 包,这在 Android 上尤其重要——因为 VpnService 只给你一个原始的 TUN fd,你得自己拆包。
真实场景:我是怎么用的
场景 1:远程访问家里的 NAS
家里的群晖 NAS 在 NAT 后面,没有公网 IP。之前用 frp 转发,但需要一台公网服务器且带宽受限。现在用 STUN Max,两台设备加入同一个房间,P2P 直连,下载速度直接拉满家里的上行带宽。
场景 2:远程开发调试
公司的开发机在内网,在外面用笔记本想访问上面跑的服务。用 STUN Max 把开发机的 8080、3000、22 端口都转发到本地,curl localhost 就能调试。
场景 3:临时文件传输
给朋友传大文件,不想经过云盘。两人打开 STUN Max,加入同一个房间,直接拖拽文件就能 P2P 传输。速度取决于两人的网络,不经过中间服务器。
性能数据
指标 | P2P 直连 | Relay 中转 | 备注 |
延迟 | 5-30ms | 50-200ms | 取决于路由 |
吞吐量 | 线速上限 | 服务器带宽 | — |
连接建立 | 2-5s | < 1s | 打洞需时间 |
加密开销 | < 3% | < 3% | AES-NI 硬件加速 |
构建产物一览
产物 | 平台 | 大小 |
Signal Server | Linux amd64 | 6.7 MB |
GUI 客户端 | macOS arm64 | 14 MB |
GUI 客户端 | Windows amd64 | 16 MB |
CLI 客户端 | Linux / macOS | 8.7-9.6 MB |
Android APK | arm64 + arm32 | 24 MB |
natcheck 工具 | 多平台 | < 5 MB |
整个项目约 16,000 行 Go 代码,其中核心逻辑 10,000 行,UI 层 4,800 行,Server 1,200 行。采用 AGPL-3.0 开源协议。
· · ·
STUN Max P2P 隧道工具 | 开源免费 | AGPL-3.0 GitHub: https://github.com/pion/stun-max 有问题?在 GitHub Issues 里聊 |
阅读原文:原文链接