20 KiB
RemoteDesk 总体架构
当前生效的目标架构以 ADR 0001 为准: Agent、Client、协议和实时通信运行时全部使用 Rust,客户端采用 winit、wgpu、egui,实时传输采用 str0m WebRTC。下文若出现 Tauri、 WebView、Go、Hysteria2、兼容模式或独立 Edge,均视为迁移历史。
1. 目标和边界
RemoteDesk 解决两个问题:
- 用 Windows 客户端连接 Windows RDP 和现代 Linux 被控端。
- 在不依赖 VDI 的前提下,连接长期存在的固定工作站。
项目以单用户和小规模设备列表为第一目标。连接目标是长期存在的固定机器,不负责创建桌面、分配用户或回收虚拟机。Linux 只作为被控端,不构建 Linux 客户端。
2. 为什么采用双通道
Windows 的 RDP 服务成熟,重复实现服务端没有价值。现代 Linux 的桌面栈以 Wayland 为主,而 xrdp 通常建立独立 Xorg 会话,不能准确复现当前桌面状态,也容易丢失 GPU 加速、桌面扩展和音频体验。Linux 被控端因此固定使用自研 Agent,不依赖桌面环境自带的 RDP 服务。
因此客户端统一,协议不强行统一:
| 目标 | 首选通道 | 说明 |
|---|---|---|
| Windows 11 Pro/Enterprise、Windows Server | RDP | 使用 Windows 系统服务 |
| GNOME/KDE 等 Wayland 桌面 | Native Desktop | Agent + Portal/PipeWire/libei |
| Xorg 桌面 | Native Desktop | Agent + XComposite/DRI3/XDamage/XTest |
| 无图形桌面的 Linux | Native Terminal | Agent + PAM/PTY |
| Linux 登录界面 | Console fallback | 后续按合成器适配 |
所有连接在 UI 中表现为相同的“主机配置”,具体通道由配置和能力探测决定。
3. 系统组件
3.1 Windows Desktop Client
Windows 客户端负责:
- 管理连接配置、收藏和最近连接。
- 使用系统密钥库读取凭据。
- 创建 RDP 或 Native 会话。
- 渲染远程画面并发送输入。
- 处理剪贴板、音频、显示器和文件传输。
- 展示延迟、帧率、码率和丢包等质量指标。
客户端内部按能力拆分:
Tauri UI (React/TypeScript)
|
Session Controller ---- Profile Store ---- Secret Store
|
+----------+--------------+-------------+
| | |
RDP Helper Native Video Terminal/Edge
| | |
IronRDP GStreamer xterm.js
客户端使用 Tauri 2 + React/TypeScript 构建主界面,终端使用 xterm.js。Linux 桌面在独立 GStreamer/D3D11 原生 helper 中完成 WebRTC、硬件解码和呈现,原始帧不进入 Tauri/WebView。Windows RDP 在另一个独立 Rust helper 中使用 IronRDP/D3D11。
3.2 RDP Adapter
RDP helper 封装 IronRDP,不向 Tauri UI 暴露 IronRDP 数据结构或图形帧。主要职责:
- NLA/TLS 认证与证书校验。
- 图形更新、动态分辨率和多显示器布局。
- 键盘布局、鼠标、Unicode 输入和组合键。
- 音频播放、麦克风和剪贴板通道。
- 本地目录重定向,默认关闭。
- 会话断开原因映射和有限次数重连。
渲染层将 IronRDP 图形更新映射为 D3D11 脏矩形上传。IronRDP 的 NLA、动态分辨率、虚拟通道和 RDP UDP multitransport 必须先通过技术验证;关键能力不足时,MVP 以系统 mstsc 作为隔离回退。
主程序与 helper 通过当前用户 ACL 限制的 Named Pipe 交换版本化控制消息。凭据不进入命令行,视频帧不进入 IPC。
3.3 Linux Agent
Linux Agent 是 Linux 唯一的被控端组件,不调用 GNOME Remote Desktop、KRdp 或 xrdp,也不提供发起远程连接的客户端界面。Agent 使用 Rust 实现,媒体管线通过 GStreamer 及其 Rust bindings 接入。
Agent 分为两个进程和权限层:
remotedesk-agent-session (graphical user)
├── Wayland: Portal/PipeWire/libei
├── Xorg: XComposite/DRI3/XDamage/XTest,XShm 仅兼容模式
├── 编码与会话信令
└── 用户音频与剪贴板
remotedesk-shell-session (target user)
├── PTY 与登录 Shell
├── 终端尺寸、信号与环境
└── 可靠 DataChannel
remotedesk-agentd (system)
├── 开机启动、设备配对和客户端授权
├── 发现已登录用户并联络会话进程
├── 更新与版本兼容检查
├── 可选的受控 uinput Helper
└── 受限 Unix Socket IPC
agentd 不捕获桌面、不编码媒体,也不读取剪贴板或终端内容。所有桌面处理保留在普通用户会话中。命令行会话由独立进程在完成 PAM/设备授权后降权到目标 UID,再创建 PTY。可选的 uinput Helper 必须代码面尽量小,并通过固定消息类型、调用方身份验证和最小设备权限限制风险。
3.4 Edge Relay
远程链路支持 Direct、Single Edge 和 Dual Edge。默认同时测量直连和 CDN 路径;当双边缘路径更优时,客户端与 Agent 分别进入最近 TURN POP,POP 间通过 CDN 私有/优质骨干传输。TURN 只转发 DTLS-SRTP/SCTP 密文,不解码、不转码、不缓存远程内容。
Agent 通过出站 TLS WebSocket 连接最近的 Rendezvous Gateway,客户端以已配对设备密钥签名会话请求。控制面只负责在线路由、信令和短期 TURN credential,不替 Agent 授权桌面或终端。详细设计见 CDN 与边缘中继。
Windows RDP 不使用 ICE/TURN。其 CDN 加速需要目标网络中的出站 L4 Edge Connector,在两端 POP 间透明转发 RDP TCP/UDP;RDP TLS/NLA 仍由 IronRDP 与目标 Windows 端到端完成。
3.5 Windows Headless Native Endpoint
Windows 被控端的高性能桌面会话使用 IDD/IddCx 创建 Headless SDR 虚拟显示器。IDD 只负责虚拟显示器、显示模式和 swap-chain 生命周期,不负责编码、网络或业务授权。当前产品约束为 SDR 8-bit;IDD 不作为 HDR10/10-bit 采集源。
正式组件边界如下:
Windows Service / Go Backend
- session、认证、配置和生命周期
- 输入路由(独立高优先级控制面)
- Hysteria2 路径和媒体策略
Windows Capture Worker(Rust/C++ 原生 helper)
- IDD frame 或 Desktop Duplication 兼容捕获
- BGRA8 GPU texture -> NV12 GPU conversion
- NVENC / AMF(VCE/VCN) / Quick Sync
- x264 / x265 / SVT-AV1 软件兜底
- 独立视频和音频队列
- 有界媒体 datagram / 控制流
IDD Driver
- Headless SDR 虚拟显示器和 4K/120 模式
Windows Headless 主路径优先直接消费 IDD GPU frame;第一阶段允许使用 Desktop Duplication 复制已存在的虚拟 output 作为兼容实现。两种路径都必须在同一 DXGI Adapter 上完成 GPU 处理,原始 BGRA8 不得进入 Go、JSON、Tauri IPC 或网络队列。
Windows Headless 视频默认支持 H.264/AVC、H.265/HEVC 和 AV1。编码器先尝试同 Adapter 的硬件后端:NVIDIA 使用 NVENC,AMD 使用 AMF/VCE/VCN,Intel 使用 Quick Sync;硬件能力验证失败时按协商结果切换 x264、x265 或 SVT-AV1。软件编码只能作为明确的兼容性降级,并自动降低分辨率、帧率或并发上限。
Windows Headless 音频独立使用 WASAPI loopback 或配置的虚拟音频 endpoint 采集,编码为 Opus,通过独立音频流发送。音频和视频使用同一会话单调时钟;输入不等待任何音频、视频帧、编码器或呈现确认。
无硬件 GPU 时启用 compatibility 模式。启动阶段依次探测硬件 DXGI Adapter、IDD/DDA output、WARP/Basic Display Adapter、硬件编码器和软件编码器;如果只有软件路径可用,允许 DDA/IDD 继续采集,但把像素路径标记为 software,并按 CPU 实测上限自动降低分辨率、帧率和并发数。compatibility 模式不得继续宣称 zero-copy、hardware_encode 或多路 4K/120 保证;strict 性能模式则在硬件编码器不可用时拒绝请求。
4. Linux 会话模式
Wayland 不允许普通进程静默截屏和任意注入输入,这是安全边界,不应通过默认 root 运行 Agent 来绕过。
4.1 Assisted Session
适合已经登录且有人可确认授权的桌面:
- Agent 请求
RemoteDesktop和ScreenCastPortal 会话。 - 桌面弹出系统授权窗口。
- Portal 返回 PipeWire 节点和 libei/EIS 输入通道。
- Agent 编码画面并建立 WebRTC 会话。
- 用户结束共享或锁屏后,根据桌面策略暂停连接。
这是跨桌面环境最标准的模式,应优先实现。
4.2 Paired Unattended Session
目标是在用户首次本地授权后允许同一设备再次连接:
- Agent 保存 Portal 返回的恢复令牌和已授权显示器信息。
- 后续连接尝试恢复 Portal 会话,并继续使用 PipeWire/libei。
- 若合成器拒绝恢复或要求再次确认,Agent 必须返回明确状态,不能静默降级到 root 抓屏。
- 不同发行版和合成器对持久授权的支持不同,能力探测结果必须展示给用户。
该模式仍由自研 Agent 实现,只复用 Wayland/Portal 提供的安全接口。
4.3 Pre-login And Lock Screen
登录前没有普通用户的 Portal/PipeWire 会话。通用实现需要 DRM/KMS 捕获、虚拟显示、uinput 和显示管理器集成,容易与合成器、安全策略及显卡驱动冲突。因此首期规则如下:
- 已登录会话锁屏后的行为按桌面能力检测,不承诺跨桌面一致。
- 物理机登录界面控制属于后续按发行版适配的实验能力。
- 不能通过让整个 Agent 以 root 运行来绕过限制。
4.4 Xorg Desktop Session
Xorg 会话 Agent 以当前图形用户身份运行,并读取该用户的 Xauthority:
- 使用 XDamage 获取变化区域,减少静态桌面复制。
- 默认通过 XComposite 获取 pixmap,并用 DRI3 导出 DMA-BUF 直达同 GPU 编码器。
- XShm/XImage 只在用户显式 compatibility 模式中启用。
- 使用 XTest 注入键盘和鼠标事件。
- 使用 XRandR 获取显示器拓扑和分辨率变化。
- 音频统一从 PipeWire 获取,不建立另一套音频协议。
Agent 只能连接自己所属用户的 Xorg 会话,不复制其他用户的 Xauthority,也不通过关闭 X server 访问控制来简化部署。
4.5 Command-line Session
纯命令行模式不需要 Wayland、Xorg 或 PipeWire:
- 已配对客户端请求目标普通用户的终端权限。
agentd验证设备权限,并通过 PAM 建立受审计的用户会话。- 独立
remotedesk-shell-session进程完成组、GID、UID 和环境降权。 - 进程创建 PTY 并执行该用户允许的登录 Shell。
- Windows 客户端使用终端控件显示 UTF-8 输出并发送输入、窗口尺寸和信号。
Linux 终端允许在配对授权中明确加入 root 用户。Agent 仍通过 PAM、独立会话进程和授权用户列表校验目标身份,不保存提权密码;未获授权的用户仍会被拒绝。
5. Native 协议
Native 通道用于 Linux Agent。第一版采用 WebRTC,避免自行设计媒体拥塞控制、时钟同步和加密传输。
5.1 通道划分
| 通道 | 内容 | 可靠性 |
|---|---|---|
| Video RTP | H.264/HEVC/AV1 视频 | 允许丢包 |
| Audio RTP | Opus 音频 | 允许少量丢包 |
| Input DataChannel | 键盘、鼠标、触控 | 有序,低延迟 |
| Control DataChannel | 显示器、质量、心跳 | 可靠有序 |
| Clipboard DataChannel | 文本、图片元数据 | 可靠有序 |
| File channel | 分块文件数据 | 可靠,可取消 |
| Terminal DataChannel | UTF-8 字节流、尺寸、信号 | 可靠有序 |
会话优先使用直连 candidate,并同时支持由边缘 Allocator 签发的短期 TURN candidate。公网模式通过 Rendezvous 转发信令;本地模式可以直接连接 Agent。两种模式共享相同设备身份、Session Ticket 和端到端 DTLS-SRTP。
5.2 差网络自适应
WebRTC 内置拥塞控制负责估算可用带宽,RemoteDesk 在其上增加会话策略:
- 使用 TWCC/GCC、RTT、抖动、NACK、PLI 和丢包 EWMA 判断链路等级。
- 协商 NACK/RTX;FEC 仅在双方支持且收益高于带宽成本时启用。
- 丢包上升时依次降低视频码率、帧率和分辨率,恢复时缓慢升档并设置迟滞。
- Opus 音频可启用 in-band FEC/DTX,优先级高于视频。
- 键盘、鼠标按键和控制消息可靠发送;高频鼠标移动只保留最新状态。
- 剪贴板和文件传输限流,严重丢包时暂停,不能阻塞输入。
- 解码端丢弃过时视频帧,连续解码失败时请求关键帧。
策略不以单次丢包采样立即切档,而使用短期/中期滑动窗口和恢复迟滞,避免画质频繁震荡。详细规则见 差网络自适应设计。
5.3 会话状态机
Idle
-> Resolving
-> Authenticating
-> Negotiating
-> Connected
-> Reconnecting
-> Connected | Failed | Closed
所有 Adapter 必须映射到同一状态机和错误类型,UI 不根据协议拼接错误字符串。
5.4 编码策略
- 默认 H.264,优先硬件编码,保证最大兼容性。
- HEVC 和 AV1 仅在双方能力协商成功时启用。
- 办公模式优先清晰度和文字边缘,限制静态画面的无效刷新。
- 动态模式优先低延迟和帧率。
- 分辨率变化应触发编码器重配置,不重建整个会话。
- 严格模式下硬件编码器或 GPU surface 导入不可用时拒绝图形会话;软件编码仅允许在用户显式开启的兼容模式中使用。
5.5 零拷贝边界
Linux Wayland 的默认发送路径为 PipeWire DMA-BUF -> GPU conversion/scale -> hardware encoder,Xorg 默认尝试 XComposite pixmap -> DRI3 DMA-BUF -> hardware encoder。Windows 默认接收路径为 hardware decoder -> GstD3D11Memory -> d3d11videosink。两端原始像素都不得经过 Rust Vec<u8>、GStreamer appsink、JavaScript、Tauri IPC 或其他 CPU 映射。
压缩后的 H.264/HEVC/AV1 码流、RTP 包和控制消息进入普通内存不属于原始帧复制。默认策略 required_end_to_end 要求 Agent 和客户端 helper 都报告经过验证的 zero_copy,否则返回 CAPABILITY_ZERO_COPY_UNAVAILABLE。跨 GPU Adapter、PipeWire memory frame、XShm/XImage、软件编解码、WebView2 opaque path 和 IronRDP CPU bitmap 均不满足该策略。用户只有显式选择 compatibility 才允许这些路径。
6. 认证与安全
6.1 RDP
- 默认启用 NLA 和 TLS。
- 首次连接不要求用户配置或确认服务器证书指纹。
- 证书变化必须阻断自动连接并提示用户重新确认。
- 密码只保存到系统密钥库,SQLite 仅保存凭据引用。
- 磁盘、剪贴板、麦克风重定向按连接配置单独授权。
6.2 Linux Agent
- 首次配对由 Agent 生成一次性短码和设备公钥。
- 客户端与 Agent 交换长期设备公钥,配对码只用于确认本次配对。
- 后续使用双向设备认证和 TLS 1.3。
- Agent 保存允许连接的客户端公钥,可本机撤销。
- 会话开始和结束必须有可见系统通知。
- 日志不得记录密码、剪贴板内容、文件内容或配对私钥。
6.3 本地数据
SQLite 保存:
- 主机名、地址、端口和协议类型。
- 显示、音频、剪贴板和质量选项。
- 证书指纹、Agent 设备 ID 和密钥库引用。
- 最近连接时间与非敏感错误摘要。
数据库不保存明文密码或私钥。
7. 用户体验
主界面直接展示远程主机列表,不设置营销首页。核心工作流:
- 新建主机,选择“Windows RDP”或“Linux Agent”,Linux 可选自动桌面、Wayland、Xorg 或命令行模式。
- 执行能力检测并给出可用通道。
- 点击连接并等待目标服务就绪。
- 进入独立会话窗口,工具栏默认自动隐藏。
- 断开后返回原主机条目,并保留可诊断的结束原因。
会话工具栏提供显示器、分辨率、全屏、本地缩放、画质、剪贴板、文件传输、统计和断开按钮。分辨率和本地缩放是两个独立设置:前者控制 RDP 会话尺寸或 Linux 编码尺寸,后者只控制客户端如何把收到的画面放入窗口。危险操作如发送安全注意序列、重启远端应放入菜单并二次确认。
分辨率支持以下模式:
- 自动跟随:默认。窗口稳定后发送新的目标尺寸,并使用防抖避免拖动时反复重配。
- 原始分辨率:保持远端显示器/桌面源尺寸,客户端只做本地缩放。
- 固定档位:720p、1080p、1440p、4K,以及经过能力校验的自定义宽高。
RDP 通过 Display Control/动态分辨率修改远程会话桌面;不支持时可提示重连后应用初始尺寸。Linux Wayland/Xorg 默认保持实体桌面模式不变,只在捕获与编码之间缩放。这样调整串流清晰度不会改变被控端显示器布局、打乱本地窗口或触发合成器权限问题。
8. 性能目标
首个稳定版本的工程目标:
| 场景 | 目标 |
|---|---|
| 办公静态桌面 | 文字清晰、低带宽、无持续满帧编码 |
| 1080p 动态画面 | 60 fps,局域环境端到端延迟可感知但不拖沓 |
| 4K 办公 | 30/60 fps 可配置,优先硬件编解码 |
| 输入 | 不因视频帧阻塞输入发送 |
| 重连 | 短时中断自动恢复,超过阈值明确失败 |
实际延迟与显卡、编码器、桌面合成器和网络条件有关,测试报告必须记录完整环境,不能只给出单个延迟数字。
9. 可观测性和诊断
- 客户端提供可导出的结构化诊断包。
- 诊断包包含版本、能力、会话状态转换和非敏感错误。
- Native 会话记录 RTT、抖动、丢包、码率、编码/解码时间和丢帧。
- RDP 会话记录协商能力、重定向通道、IronRDP 错误和 UDP multitransport 状态。
- 日志默认滚动保存并限制大小。
- 导出前对用户名、地址和路径进行可选脱敏。
10. 测试矩阵
最低覆盖:
- Windows 11 Pro 与 Windows Server 的 RDP。
- Ubuntu/Fedora 当前稳定版 GNOME Wayland 上的自研 Agent。
- KDE neon 或主流发行版 Plasma 6 Wayland 上的自研 Agent。
- 至少一种 GNOME/KDE Xorg 会话。
- 无图形环境的 Debian/Ubuntu Server 命令行会话。
- NVIDIA、AMD 和 Intel 至少各一种硬件编解码环境。
- 单显示器、双显示器、HiDPI 和动态分辨率。
- 中文输入、剪贴板、大文件和音频。
- 证书变化、错误密码、锁屏、休眠、VM 重启和断网重连。
测试分层为核心状态机单元测试、协议适配集成测试、虚拟机端到端测试和长时间稳定性测试。
11. 主要风险
| 风险 | 应对 |
|---|---|
| IronRDP 关键 RDP 能力不足 | M0 设置功能门槛,保留 mstsc 隔离回退 Adapter |
| WebView2 GPU 无法证明内部 surface 路径 | Linux 桌面默认使用原生 video helper,WebView2 仅显式兼容模式 |
| 驱动或桌面不提供可导入的 GPU surface | 默认拒绝图形会话;用户显式启用 compatibility 后才允许回退 |
| Tauri 与原生 helper 生命周期不一致 | Named Pipe heartbeat、generation、独立崩溃恢复和幂等关闭 |
| Web 输入无法覆盖系统组合键/Raw Input | 系统组合键走 Rust command,高要求场景切换原生 helper |
| 差网络下视频震荡或输入阻塞 | WebRTC GCC + 分层退化 + 有界独立队列 + 恢复迟滞 |
| Wayland Portal 行为随桌面变化 | 维护能力探测和发行版测试矩阵 |
| Xorg 捕获权限配置错误 | 只使用目标用户 Xauthority,禁止关闭 X 访问控制 |
| PTY 远程终端扩大权限面 | PAM 建立会话、强制降权、设备权限独立控制 |
| 无人值守 Linux 缺乏统一接口 | 首次授权后尝试 Portal 恢复令牌,登录界面单独适配 |
| 硬件编码器兼容性 | 默认拒绝非零拷贝会话;显式 compatibility 才允许 H.264 软件回退 |
| 输入法和键盘布局错误 | 统一物理键与 Unicode 输入模型,专项测试中英文布局 |
| IronRDP/GStreamer 等依赖安全更新 | 固定版本、生成 SBOM、建立升级回归测试 |