1. 先建立共同语言:什么是「远程桌面」
远程桌面要解决的问题很简单:
人坐在 本机 A ,操作 远端机 B 上的桌面(鼠标键盘进、画面出),就像坐在 B 跟前一样。
对 Windows 来说,业界最常用的协议是 RDP(Remote Desktop Protocol) ,默认监听 TCP 3389。
注意区分三层概念:
| 概念 | 是什么 | 举例 |
|---|---|---|
| 协议 | 双方约定怎么传键鼠、画面、剪贴板等 | RDP、VNC、SSH |
| 服务端 | 远端机上接受连接、提供桌面会话的一方 | Windows「远程桌面服务 / TermService」 |
| 客户端 | 本机上发起连接、显示画面的一方 | mstsc、Guacamole 前端、IronRDP |
本项目里,能源站 / 照明系统 等机器扮演的是 RDP 服务端 (只需开 3389);门户客户端要做的是选一种 客户端方案 去连它们。
2. Windows 建立远程桌面的原理
2.1 远端机(被控端)要具备什么
在 Windows 上打开「设置 → 系统 → 远程桌面」并允许连接后,大致会发生:
- 远程桌面服务 (
TermService)启动,并监听0.0.0.0:3389(或你改过的端口)。 - 系统准备好 会话(Session) 机制:本地登录是 Session,远程登录也是 Session;远程用户登录后得到自己的桌面环境(或接管已有会话,取决于策略与版本)。
- 可选但常见的安全层:
- TLS / 证书(传输加密)
- NLA(Network Level Authentication):先用凭据认证,再进入完整桌面会话,减少未认证连接占用资源
- 防火墙放行 3389(域策略 / 本机防火墙)
远端机不必 安装 Guacamole、不必装任何第三方远程软件------微软内置 RDP 服务端即可。
本项目设计也是:远端只开 3389。
2.2 一次典型连接时序(简化)
text
本机客户端 远端 Windows (3389)
| |
| 1. TCP 连接到 host:3389 |
|----------------------------------->|
| 2. 能力协商(协议版本、加密、GFX...) |
|<---------------------------------->|
| 3. 身份认证(用户/密码/域/智能卡...) |
|----------------------------------->|
| 4. 建立会话,进入桌面 |
|<---------------------------------->|
| 5. 持续双向流: |
| ← 画面/光标/剪贴板/声音... |
| → 键鼠/触控/文件重定向... |
|<---------------------------------->|
要点:
- 画面:服务端把桌面变化编码后推给客户端(现代 RDP 常用 GFX / RemoteFX 一类图形管线,效率高于「整屏位图硬刷」)。
- 输入:客户端把键盘、鼠标事件编码发回服务端,由服务端注入到对应会话。
- 这是二进制私有协议:浏览器不能「直接」说 RDP;要么用系统客户端(mstsc),要么在中间加一层翻译,要么在浏览器里跑一套完整的 RDP 协议栈(WASM)。
2.3 凭据从哪来(和本项目的关系)
mstsc 可以弹窗让用户手输账号密码,也可以事先用 cmdkey 把凭据写入 Windows 凭据管理器,再无感拉起 mstsc /v:host。
本项目「微软原生」模式走的就是:读配置里的账号密码 → cmdkey → mstsc。
Web / WASM 方案则是把同一份 host/user/pass 交给自研编排层 ,由 guacd 或 IronRDP 去完成 RDP 握手,而不是交给系统的 mstsc。
3. 三种方案分别是什么
下面三个名字,经常被混在一起谈,其实处在不同层次。
text
┌─────────────────────────────────────────────────────────────┐
│ 用户眼睛看到的「桌面画面」 │
└─────────────────────────────────────────────────────────────┘
│ │ │
┌────▼────┐ ┌─────▼─────┐ ┌─────▼─────┐
│ mstsc │ │ Guacamole │ │ IronRDP │
│ 系统窗口 │ │ 网页 Canvas│ │ 网页 Canvas│
└────┬────┘ └─────┬─────┘ └─────┬─────┘
│ │ │
│ ┌─────▼─────┐ │
│ │ guacamole │ │
│ │ -lite / │ │
│ │ 网关 WS │ │
│ └─────┬─────┘ │
│ │ │
│ ┌─────▼─────┐ │
│ │ guacd │ │
│ │ 协议翻译 │ │
│ └─────┬─────┘ │
│ │ │
└──────────┬─────────┴────────┬───────────┘
│ │
▼ ▼
远端 Windows RDP (3389) ------ 三种最终都要连这里
3.1 mstsc(微软原生客户端)
是什么
Windows 自带的「远程桌面连接」程序,可执行文件一般是:
text
%SystemRoot%\System32\mstsc.exe
怎么工作
- 本机直接对
host:3389发起 原生 RDP 连接。 - 系统弹出或使用已存凭据完成认证。
- 在 独立的系统窗口 里渲染远端桌面(不是嵌在你的 Vue/Tauri 页面里)。
在本项目中的角色
设置里的「微软原生」:cmdkey 写凭据 → 启动 mstsc。
稳定、零第三方依赖,但体验是「跳出门户、打开系统远程桌面窗口」。
优点
- Windows 自带,无需打包 guacd / Node / WASM
- 兼容性最好(NLA、证书、打印机/剪贴板/驱动器重定向等成熟)
- 性能通常最好(本地原生渲染)
- 内网离线部署最省事
缺点
- 无法嵌进应用窗口(或很难无缝嵌;本质是另一个进程的 HWND)
- 凭据落在 Windows 凭据管理器,生命周期与卸载策略要单独考虑
- 多会话、统一 UI、水印、审计等产品化能力弱(除非再包一层)
3.2 guacd(Apache Guacamole 代理)+ 网页前端
是什么
guacd 是 Apache Guacamole 的 服务端代理守护进程(C 语言)。它自己不是「给用户看的窗口」,而是:
一边说 Guacamole 协议 (给浏览器用的文本/指令协议),
一边说 RDP/VNC/SSH...(连真实远端)。
浏览器端用 guacamole-common-js 在 Canvas 上画图;中间通常还有一层 WebSocket 网关。本项目用的是:
- guacd:RDP ↔ Guacamole 协议翻译
- guacamole-lite(Node):浏览器 WebSocket ↔ guacd
- 前端:内嵌 Guacamole 客户端
完整链路(本项目 Web 模式)
text
Tauri WebView
└── guacamole-common-js (Canvas)
│ WebSocket (ws://127.0.0.1:随机端口/?token=...)
▼
node-gateway (guacamole-lite)
│ Guacamole 协议 TCP
▼
guacd.exe
│ RDP (3389)
▼
远端 Windows
用户感知:「还在门户窗口里,桌面嵌在页面中」。
远端感知:「就是一个普通 RDP 客户端连上来了」。
为什么需要 guacd
浏览器不能直接发 RDP 二进制流(安全模型 + 协议复杂度)。Guacamole 的经典解法是:把「会说 RDP 的重活」放到本机/服务器上的 guacd,浏览器只处理相对简单的 Guacamole 协议。
优点
- 可嵌窗:体验统一在 Tauri 窗口内
- 生态成熟(运维界用 Guacamole 做堡垒机很常见)
- 同一套栈还可扩展 VNC/SSH(本项目只用 RDP)
- 凭据可由应用签发一次性 token,不必先弹 mstsc 登录框
缺点
- 组件多:guacd + Node 网关 + 前端 JS,任一挂掉都要编排重启
- Windows 版 guacd :Apache 不提供官方
guacd.exe;Docker 镜像是 Linux;社区移植/预编译少且老旧 → 打包进 Win 客户端是最大现实阻力 - 安装包体积大(guacd+DLL + 便携 Node + node_modules)
- 性能与功能(打印机、部分 GFX/NLA 组合)通常弱于 mstsc
- 多进程,排障成本高
和「第三方封装」的关系(调研结论)
- Docker
guacamole/guacd:最常见封装,但是 Linux 容器,不是原生 Win exe - guacamole-lite :封装的是 WebSocket 网关,不是 guacd 本身
- 社区 Windows 移植 (如源码级 port):多为过时版本、需自行编译,鲜有可靠现成
guacd.exe+DLL Release
所以:「有第三方封装」≠「有一份能直接塞进 NSIS 安装包的稳定 Windows guacd」。
3.3 IronRDP-WASM(浏览器内 RDP 协议栈)
是什么
IronRDP 是 Devolutions 开源的 纯 Rust 实现的 RDP 客户端 。
其中的 WASM / Web 产物可以在浏览器(或 WebView2)里跑完整 RDP 逻辑,用 Canvas 画桌面。
怎么工作(概念)
text
Tauri WebView
└── ironrdp.wasm + JS 胶水
│ 需要一条「到远端 3389」的字节通道
│ (浏览器不能随意 TCP,通常要:
│ WebSocket / WebTransport 代理,或 Tauri 本地转发)
▼
(可选)本机很薄的 TCP↔WS 转发
│ RDP
▼
远端 Windows :3389
与 Guacamole 的关键差异:
| Guacamole | IronRDP-WASM | |
|---|---|---|
| RDP 协议在哪实现 | guacd(本机/服务器原生进程) | 浏览器里的 WASM |
| 是否需要 guacd | 需要 | 不需要 |
| 中间层 | guacamole 协议 + 常驻代理 | 主要是「字节管道」转发 |
| 典型体积 | guacd + Node 较大 | WASM 量级通常更小(约数 MB 级,视构建而定) |
优点
- 无 guacd:避开 Windows 预编译二进制难题
- 可嵌在 WebView 内,接近 Guacamole 的产品体验
- 组件更少(相对 guacd + guacamole-lite)
- 与「纯前端 + 薄网关」架构契合 Tauri
缺点
- 仍不是零后端 :浏览器一般不能直连任意 TCP 3389,需要 本机或服务器上的转发/网关(工作量小于 guacd,但不是零)
- WebView2 / WASM 工具链、剪贴板、音频、分辨率自适应等要逐项验证
- 相对 mstsc,企业环境边角兼容性(NLA、证书、特殊策略)可能踩坑
- 本项目前期调研推荐过 IronRDP;现行 Web 主路径已切到 IronRDP-WASM + Devolutions Gateway,guacd 已弃用
4. 对照总表
| 维度 | mstsc | guacd + Guacamole Web | IronRDP-WASM |
|---|---|---|---|
| 画面出现在哪 | 系统独立窗口 | 应用内 Canvas | 应用内 Canvas |
| 谁实现 RDP | 微软客户端 | guacd | WASM 内 IronRDP |
| 远端要求 | 仅 3389 | 仅 3389 | 仅 3389 |
| 本机额外进程 | 无(系统自带) | guacd + Node 网关 | 合规转发(如 Devolutions Gateway / RDCleanPath) |
| Win 客户端打包难度 | 极低 | 高(缺官方 guacd.exe) | 中(WASM + 转发;转发有官方 Win 发行可参考) |
| 内网离线友好 | 最好 | 需预置全部 sidecar | 需预置 WASM + 转发组件 |
| 性能 / 兼容 | 通常最好 | 中等 | 中等(视实现成熟度) |
| 本项目现状 | ✅ 已实现「原生」 | ❌ 已弃用 | ✅ 现行「Web」路径(Gateway + ironrdp-web) |
5. 「需验证转发与 WASM」是什么意思?
这句话不是说 IronRDP「理论上不行」,而是说:接入前有两块必须真机跑通的工程,不能当成已交付。
5.1 WASM 是什么(要验证的第一块)
WASM(WebAssembly) = 把 IronRDP 的 RDP 客户端编译成浏览器能跑的二进制模块(通常是 *.wasm + 一小段 JS 胶水)。
在本项目里它会跑在 Tauri 的 WebView2 里,负责:
- 完成 RDP 握手 / NLA / 画桌面到 Canvas
- 把键鼠事件编码成 RDP 发回去
要验证的具体事项:
| 检查项 | 为什么 |
|---|---|
能否用 wasm-pack / 官方 web-client 打出可用产物 |
工具链、依赖版本常踩坑 |
WebView2 能否加载该 .wasm |
CSP、MIME、路径、跨域 |
| 画布是否出画、分辨率缩放是否正常 | 渲染与输入事件 |
| 剪贴板 / 键盘布局 / 重连 | 产品可用性 |
| 目标机 Win7~Win11 兼容 | 甲方环境跨版本(Win7 风险更高) |
这和「有没有 guacd.exe」是两类问题:WASM 是前端协议栈能不能在我们窗口里活起来。
5.2 转发是什么(要验证的第二块)
浏览器 / WebView2 不能 像 mstsc 那样随便打开一条到 host:3389 的原始 TCP。
所以 WASM 客户端通常只能走 WebSocket(或自定义 transport) ,中间必须有人把字节接到真正的 RDP 端口------这就是文档里说的 转发(proxy / gateway)。
text
WebView 里的 ironrdp.wasm
│ WebSocket(浏览器允许)
▼
本机「转发」进程(只应绑 127.0.0.1)
│ TCP 3389(RDP 需要)
▼
远端 Windows
重要:不是任意 WS→TCP 都行。
官方 ironrdp-web 默认期望代理理解 RDCleanPath 扩展(先处理一段预连接/证书信息,再进入 RDP)。
随便写一个「WebSocket 字节透传」往往不够;社区常见可用方案是:
- 使用 Devolutions Gateway(官方配套、有 Windows 发行,实现了 RDCleanPath),或
- 自己实现 RDCleanPath,或
- 不用 WASM,改在 Tauri Rust 进程内直接跑原生 IronRDP(可直连 TCP,但要把画面嵌进 UI 的方式另做设计)
本仓库早期曾写过简易 rdp_gateway(裸 WS↔TCP),那只是预研骨架;不能默认它已满足现行 ironrdp-web 。
所以「验证转发」=:选定一种合规网关/transport,并在真机 RDP 上连通。
5.3 和 guacd 路线对比(为何常觉得 IronRDP 更合适)
| Guacamole / guacd | IronRDP-WASM | |
|---|---|---|
| 重依赖 | Windows 上难找官方 guacd.exe |
不需要 guacd |
| 中间层 | guacd + Node guacamole-lite | 转发(常为 Devolutions Gateway 或自研 RDCleanPath) |
| 画面 | 嵌窗 Canvas | 嵌窗 Canvas |
| 打包 | 卡在第三方 Win guacd | 卡在「WASM 构建 + 合规转发」是否跑通 |
| 对本项目 | 现有 Web 模式已铺管线,但缺 guacd 二进制 | 更贴「客户端自带、嵌窗、少 C 依赖」的目标,但要重做/换 Web 分支 |
结论可以概括成:
- 你的直觉有道理:就「避开 Windows guacd」和「嵌在门户里」而言,IronRDP 往往更适合我们。
- 「需验证转发与 WASM」的意思是:适合 ≠ 已经能用;还差两块可演示的验收,而不是再去找 guacd.exe。
5.4 若决定切到 IronRDP,建议的验收顺序
- WASM:官方 web-client / 预构建能否在本机浏览器出画(先不管门户)。
- 转发:Devolutions Gateway(或等价 RDCleanPath)本机启动,WASM 经它连上一台真实 3389。
- 嵌入 Tauri :
RdpViewer改为加载 IronRDP 页;凭据仍由 Rust 下发。 - 兼容:至少测一台 Win10/11;有条件再测 Win7。
- 保留 mstsc:作为设置里的兜底(已通,不要删)。
6. 和本项目目标的匹配
门户目标可以概括成:
- 用户只点卡片,尽量少感知「又开了一个系统工具」
- 凭据由客户端配置/后台管理,不要让用户每次手输
- 内网环境,目标机不装额外软件,安装包尽量自包含
- PoC 要尽快可演示,也要能讲清正式方案风险
据此:
| 目标 | mstsc | Guacamole/guacd | IronRDP-WASM |
|---|---|---|---|
| 嵌在门户窗口内 | ❌ | ✅ | ✅ |
| 远端零改造(只开 3389) | ✅ | ✅ | ✅ |
| 内网安装包自包含 | ✅ | ⚠️ 卡在 guacd.exe | ⚠️ 需验证转发与 WASM |
| 实现与运维复杂度 | 低 | 高 | 中 |
| 当前可演示性 | 立刻可用 | 差 guacd 二进制则 Web 不通 | 需重新接入 |
务实结论(给决策用):
- 要稳定演示 / 内网交付兜底 → 保留并优先保证 mstsc 原生模式(已通)。
- 要窗口内嵌体验 → 使用现行 IronRDP-WASM + Devolutions Gateway(已替代 guacd);保留 mstsc 兜底。
- 不要再投入 Windows guacd 二进制寻找;官方路径是 Gateway + IronRDP。
7. 一张图看清「建立连接」时你在用谁
text
用户点击「打开远程」
│
▼
读取有效模式(全局 defaultMode / 项目 rdpMode)
│
├── native ──────────────────────────────────────┐
│ ▼
│ cmdkey 写入凭据
│ ▼
│ 启动 mstsc /v:host
│ ▼
│ 系统窗口 ←──RDP──→ 远端:3389
│
└── web ─────────────────────────────────────────┐
▼
本地 Devolutions Gateway
是否就绪?
│
┌────────是──────────┴────────否──┐
▼ ▼
签发 ASSOCIATION token, 若有 webUrl → 外链兜底
打开内嵌 IronRDP 画面 否则提示失败 / 改用原生
│
▼
Canvas ←WS /jet/rdp→ Gateway ─RDP→ 远端:3389
(历史 Guacamole / guacd 路径已弃用。)
8. 常见误解
-
「装了 Guacamole,远端也要装?」
否。Guacamole/guacd 装在 客户端或网关机;远端只开 RDP。
-
「guacamole-lite 能代替 guacd?」
否。lite 只做 WebSocket 与会话编排;不会自己说 RDP。
-
「IronRDP 完全不用本机任何服务?」
几乎不行。浏览器环境通常仍要一条到 3389 的转发通道;只是不必再跑完整 guacd。
-
「mstsc 和 RDP 是两个东西?」
RDP 是协议;mstsc 是微软对该协议的官方客户端之一。
-
「Web 模式更不安全 / 更安全?」
不绝对。安全取决于凭据存放、token 时效、是否只绑 127.0.0.1、日志是否落盘等。mstsc 用系统凭据库;Web 模式用应用自己的编排------各有审计与泄露面,需要产品层统一设计。