多端形态:CLI/IPC/Web/桌面/Android
专栏:VNT 2.0 组网源码 · 第 10 / 11 篇:::info 学习目标 完成本篇后你能够:解释”核心与载体分离”的架构收益;对比五种载体的控制通道取舍;说出 Android 端 startTun(fd) 的协作模型。 前置:第 3 篇完成。预计时长:60 分钟。 :::
:::note 本章术语速查(新手建议先读)
- IPC(进程间通信):同一台电脑上两个进程交换数据(管道/socket/共享内存等)。
- axum:Rust 最流行的 Web 框架之一。
- oneshot:一次性通道——发一个值,接收方收到即完成。
- RustEmbed:编译时把静态文件(如前端产物)嵌进二进制。
- FFI:两种语言互相调用的边界(如 Java 调 Rust)。
- panic:Rust 的“程序崩溃”——跨语言边界时必须拦住。 :::
vnt 2.0 的架构决定:所有组网逻辑收进 vnt-core 一个 crate,载体只做壳。同一个人机能力,五种形态各按场景取用:
vnt2_cli / vnt2_ctrl:TCP IPC 而非管道
vnt2_cli 是干活的常驻进程;查询交给独立的 vnt2_ctrl(整个文件 43 行,4 个子命令 Info/Ips/Clients/Route 映射为 protobuf IpcCmd)。两者的通道是 loopback TCP(默认 11233)+ protobuf + 帧编解码——不是 unix socket。
两个工程细节值得学:PORT 文件的锚定——写进”可执行文件同目录”而非 CWD(否则换个目录启动就读不到了);PORT 文件只由绑定到默认端口的实例写——第二个实例(显式指定端口或冲突退避到随机端口)都不写,防止多实例互相覆盖导致查询到错误的进程。客户端发现顺序:--port 参数 > PORT 文件 > 默认 11233,连接 3 秒超时、响应 5 秒超时——一个只读查询工具的健壮性也毫不将就。
vnt2_web:axum 管理面
vnt2_web 面向无桌面环境(服务器/NAS):启动时生成 48 字符随机 token 打进访问 URL,浏览器里管理多个组网实例(每个实例独立的配置 TOML、状态机 Stopped/Starting/Running、冲突检测)。13 个 REST API 走 Bearer 鉴权,Vue3 前端经 RustEmbed 编进二进制。token 消费后 history.replaceState 从 URL 抹除——细节见功力。
vnt-desktop:进程内直调,不开端口
桌面端(Tauri 2)与 Web 共用同一套 Vue 应用(vnt-web/ui 通过 vite alias 共享),差异只在桥接层:桌面前端的 __VNT_IPC_REQUEST__ 不走 HTTP,而是 invoke Tauri 命令 api_request → 进程内 oneshot 直调 axum Router——
// vnt-desktop/src-tauri/src/lib.rs:136-151(节选)
#[tauri::command]
async fn api_request(..., path: String, ...) -> Result<serde_json::Value, String> {
if !path.starts_with("/api/") {
return Err("只允许调用 VNT API".to_string());
}
state.service.request(&method, &path, body).await...
}
同一套 API、零网络端口、零 token 管理(进程内没有别人)。需要浏览器访问时按需开启(web_access.toml,token 至少 16 字符)——桌面端把”要不要暴露网络服务”变成一个显式的用户决定。这是三种控制通道里安全模型最干净的一种。
vnt-jni:Android 的 fd 移交
Android 不能自己建 TUN,必须走系统 VpnService。JNI 层(cdylib,jni 0.21)的协作模型:
所有 JNI 入口用宏捕获 panic(防跨 FFI 展开)、实例用 i64 句柄表管理、配置与查询全走 JSON 字符串——FFI 边界尽量窄的典型实践。
常见踩坑
- vnt2_ctrl 连不上——cli 是否启动、PORT 文件位置(exe 旁)、
ctrl_port=0是否显式禁用; - Web token 丢了——看启动日志的
Web access URL,或--token固定; - Android 上 establish 返回 -1——VPN 权限未授予或重复 establish。
随堂练习(带验收标准)
- 同时跑 vnt2_cli 与 vnt2_ctrl,用
ss -tnp确认 11233 的 IPC 连接; - 起一个 vnt2_web,用两个浏览器标签管理两个组网实例。验收:实例间状态互不干扰;
- 进阶:对照
vnt-web/ui与vnt-desktop/src/main.js,画出”同一 Vue 应用如何适配两种宿主”的桥接图。