收藏
Linux开发架构之路
CrossDesk是一个跨平台远程桌面系统,由三个项目组成:
| 项目 | 角色 | 语言 | 构建系统 |
|---|---|---|---|
| crossdesk | APP客户端(桌面端,既可控制也可被控) | C++17 | xmake |
| crossdesk-server | 信令服务器(WebSocket+TLS) | C++17 | xmake |
| crossdesk-web-client | Web客户端(浏览器端,仅观看/控制) | JavaScript | 静态文件/GitHub Pages |
外部依赖:coturn (TURN/STUN服务器,用于NAT穿透中继)
| 消息类型 | 方向 | 用途 |
|---|---|---|
| ping / pong | 双向 | 心跳保活 |
| login | C→S→C | 设备注册/认证,返回设备ID和密码 |
| join_transmission | C→S | 加入传输会话(观看端发起) |
| user_join_transmission | S→C | 通知被控端有人加入 |
| user_leave_transmission | C→S→C | 离开传输会话 |
| offer | C→S→C | WebRTC SDP Offer(被控端→观看端) |
| answer | C→S→C | WebRTC SDP Answer(观看端→被控端) |
| new_candidate_mid | C→S→C | ICE Candidate交换 |
| query_user_id_list | C→S | 查询会话中的用户列表 |
| recent_connections_presence | C→S | 查询设备在线状态 |
| presence / presence_update | S→C | 设备在线状态响应/推送 |
通过WebRTC DataChannel传输的控制指令(JSON格式):
| ControlType | 值 | 用途 | 数据字段 |
|---|---|---|---|
| mouse | 0 | 鼠标事件 | {x, y, s, flag} (坐标归一化0~1) |
| keyboard | 1 | 键盘事件 | {key_value, flag} (0=按下, 1=释放) |
| audio_capture | 2 | 音频采集开关 | {audio_capture: bool} |
| host_infomation | 3 | 主机信息(显示器列表等) | {host_name, display_num, displays[]} |
| display_id | 4 | 切换显示器 | {display_id: number} |
定位:跨平台桌面应用,既可作为被控端(共享屏幕),也可作为控制端(远程操控)。
源码模块结构:
crossdesk/src/├── app/ # 应用入口│ ├── main.cpp # main() 入口│ └── daemon.cpp/h # 守护进程├── gui/ # GUI层 (SDL3 + ImGui)│ ├── render.cpp/h # 主渲染器,核心调度中心│ ├── render_callback.cpp # minirtc 回调处理(视频/音频/数据/信令/连接状态)│ ├── panels/ # UI面板│ │ ├── local_peer_panel.cpp # 本机信息面板(设备ID、密码)│ │ ├── remote_peer_panel.cpp # 远程连接面板(输入对方ID连接)│ │ └── recent_connections_panel.cpp # 最近连接列表│ ├── toolbars/ # 工具栏│ │ ├── title_bar.cpp # 标题栏│ │ ├── control_bar.cpp # 控制栏(全屏/鼠标控制/音频等)│ │ └── status_bar.cpp # 状态栏│ ├── windows/ # 各功能窗口│ │ ├── main_window.cpp # 主窗口│ │ ├── stream_window.cpp # 远程画面显示窗口│ │ ├── control_window.cpp # 控制面板窗口│ │ ├── server_window.cpp # 服务器模式窗口│ │ ├── file_transfer_window.cpp # 文件传输窗口│ │ ├── main_settings_window.cpp # 设置窗口│ │ ├── server_settings_window.cpp # 服务器设置│ │ ├── about_window.cpp # 关于窗口│ │ ├── connection_status_window.cpp # 连接状态│ │ └── update_notification_window.cpp # 更新通知│ ├── tray/ # 系统托盘 (Windows)│ └── assets/ # 资源(字体、图标、布局、多语言)├── screen_capturer/ # 屏幕采集(跨平台)│ ├── screen_capturer.h # 抽象接口│ ├── linux/ # X11 采集 (XShmGetImage)│ ├── windows/ # DXGI / WGC / GDI 采集│ └── macosx/ # ScreenCaptureKit 采集├── speaker_capturer/ # 系统音频采集(跨平台)│ ├── linux/ # PulseAudio│ ├── windows/ # WASAPI│ └── macosx/ # CoreAudio├── device_controller/ # 输入设备控制(跨平台)│ ├── device_controller.h # 控制类型定义 + RemoteAction 序列化│ ├── mouse/ # 鼠标控制 (linux/windows/mac)│ └── keyboard/ # 键盘控制 (linux/windows/mac)├── common/ # 通用工具(平台检测、显示器信息)├── config_center/ # 配置中心(SimpleIni)├── path_manager/ # 路径管理├── thumbnail/ # 缩略图生成(stb_image, AES加密)├── tools/ # 工具(剪贴板、文件传输)│ ├── clipboard.cpp/h # 剪贴板操作│ └── file_transfer.cpp/h # 文件传输逻辑├── autostart/ # 开机自启├── version_checker/ # 版本检查(HTTP请求)└── log/ # 日志 (spdlog)核心子模块minirtc(WebRTC引擎,作为git submodule):
submodules/minirtc/src/├── api/minirtc.h # C API 接口(CreatePeer, JoinConnection, SendVideoFrame等)├── rtc/ # RTC 顶层封装├── pc/ # PeerConnection 管理├── ws/ # WebSocket 客户端├── ice/ # ICE 连接(基于 libnice)├── transport/ # 传输层(SRTP, paced sender)├── rtp/ # RTP 打包/解包├── rtcp/ # RTCP 反馈├── srtp/ # SRTP 加密├── media/ # 编解码│ ├── video/encode/ # 视频编码 (OpenH264, AOM/AV1, SVT-AV1, VideoToolbox, NVENC)│ ├── video/decode/ # 视频解码 (OpenH264, dav1d, AOM, VideoToolbox, NVDEC)│ └── audio/ # 音频编解码 (Opus)├── fec/ # 前向纠错 (OpenFEC)├── qos/ # QoS 控制├── statistics/ # 网络统计└── frame/ # 帧管理第三方依赖:
| 库 | 用途 |
|---|---|
| SDL3 | 窗口/渲染/输入事件 |
| ImGui (docking) | GUI框架 |
| minirtc (submodule) | 自研WebRTC引擎 |
| spdlog | 日志 |
| nlohmann_json | JSON |
| openssl3 | TLS/加密 |
| cpp-httplib | HTTP客户端(版本检查) |
| tinyfiledialogs | 文件对话框 |
| libyuv | 图像格式转换 |
| libnice | ICE/NAT穿透 |
| websocketpp + asio | WebSocket客户端 |
| OpenH264 / AOM / SVT-AV1 / dav1d | 视频编解码 |
| libopus | 音频编解码 |
| libsrtp | SRTP加密 |
| libdatachannel | DataChannel |
| OpenFEC | 前向纠错 |
定位:WebSocket信令服务器,负责设备注册、认证、消息路由,不参与媒体传输。
源码结构:
crossdesk-server/src/├── main.cpp # 入口:解析端口参数,启动 SignalServer├── signal_server.cpp/h # WebSocket服务器(websocketpp + TLS)├── signal_negotiation.cpp/h # 信令处理:login/join/offer/answer/ICE 路由├── transmission_manager.cpp/h # 会话管理:host/guest 绑定,用户↔连接映射├── presence_manager.cpp/h # 设备在线状态管理,推送上下线通知├── device_db_manager/ # SQLite数据库:设备注册、密码验证、在线状态│ ├── device_db_manager.h│ └── device_db_manager.cpp├── common/ # 通用工具(字符串哈希、ICE用户名提取)└── log/ # 日志 (spdlog, 滚动文件)关键设计:
WebSocket: websocketpp 0.8.2+TLS,默认端口9090
会话模型: 一个transmission由一个host(被控端)和多个guest(观看端)组成
认证: 设备首次登录自动分配9位数字ID+6位密码,SHA256+salt存储于SQLite
Web客户端: user_id == "web"时分配临时web-{id},断开时自动清理
消息路由: offer/answer/ICE按remote_user_id点对点转发
活性检测: 后台线程每10秒检查,无活动则断开
数据库 (SQLite):
devices: device_id, password_salt, password_hash
device_id_seq: next_id (自增序列)
device_presence: device_id, online, updated_at
配置:
| 配置项 | 默认值 |
|---|---|
| 端口 | 9090 (CLI参数) |
| TLS证书 | /var/lib/crossdesk/certs/api.crossdesk.cn_bundle.crt |
| TLS私钥 | /var/lib/crossdesk/certs/api.crossdesk.cn.key |
| 数据库 | /var/lib/crossdesk/db/crossdesk-server.db |
| 日志 | /var/log/crossdesk/ |
定位:纯前端Web应用,通过浏览器WebRTC API观看和控制远程桌面。
文件结构:
crossdesk-web-client/├── index.html # 主页面:连接表单、视频/音频元素、虚拟鼠标/键盘├── web_client.js # 核心逻辑:WebSocket信令、WebRTC连接、面板UI├── control.js # 输入处理:鼠标/键盘/虚拟控件、DataChannel消息发送├── styles.css # 样式:响应式布局、虚拟控件├── manifest.json # PWA配置├── CNAME # GitHub Pages 自定义域名 (web.crossdesk.cn)├── README.md # 说明文档└── LICENSE # LGPL v3核心功能:
| 功能 | 实现方式 |
|---|---|
| 信令连接 | WebSocket(wss://api.crossdesk.cn:9099) |
| 视频显示 | HTML5 <video>元素, object-fit: contain |
| 音频播放 | HTML5 <audio>元素 |
| 鼠标控制 | Pointer Lock(桌面)/触摸(移动端) |
| 键盘控制 | 键盘事件捕获+虚拟键盘(移动端) |
| 多显示器 | 通过DataChannel发送display_id切换 |
| 缩放 | 双指缩放1.0x~3.0x(移动端) |
| 心跳 | ping每3秒, 超时10秒自动重连 |
默认配置 (web_client.js):
const DEFAULT_CONFIG = { signalingUrl: "wss://api.crossdesk.cn:9099", iceServers: [ { urls: ["stun:api.crossdesk.cn:3478"] }, { urls: ["turn:api.crossdesk.cn:3478"], username: "crossdesk", credential: "crossdeskpw" } ], heartbeatIntervalMs: 3000, heartbeatTimeoutMs: 10000, reconnectDelayMs: 2000, clientTag: "web"};核心关系:
crossdesk-server是中心枢纽,负责信令中转,不接触媒体数据
crossdesk和crossdesk-web-client都通过WebSocket连接到server进行信令交换
信令完成后,crossdesk和crossdesk-web-client建立WebRTC P2P连接直接传输媒体
当P2P不可达时,通过coturn TURN服务器中继媒体流
crossdesk既可以是被控端(发送屏幕/音频,接收控制指令),也可以是控制端(接收屏幕/音频,发送控制指令)
crossdesk-web-client只能作为控制端/观看端(接收屏幕/音频,发送控制指令)
Linux环境下需安装以下包:
sudo apt-get install -y software-properties-common git curl unzip build-essential libx11-dev libxrandr-dev libxinerama-dev libxcursor-dev libxi-dev libxcb-randr0-dev libxcb-xtest0-dev libxcb-xinerama0-dev libxcb-shape0-dev libxcb-xkb-dev libxcb-xfixes0-dev libxfixes-dev libxv-dev libxtst-dev libasound2-dev libsndio-dev libxcb-shm0-dev libasound2-dev libpulse-dev编译
git clone https://github.com/kunkundi/crossdesk.gitcd crossdeskgit submodule init git submodule updatexmake b -vy crossdesk编译的时候因为还要拉取第三方库(glib,openssl3-3.3.2.zip ..等,主要是minirtc依赖很多第三方库)所以比较慢,需要耐心等待,可以尝试
# 或者使用 GitHub 镜像代理xmake g --proxy_hosts=github.com:https://ghfast.top然后再继续
xmake b -vy crossdesk可能的报错:
/usr/bin/git clone https://gitlab.gnome.org/GNOME/glib.git -b 2.84.1 --depth 1 --recursive --shallow-submodules -c core.fsmonitor=false source.tmp/glibCloning into 'source.tmp/glib'...fatal: unable to access 'https://gitlab.gnome.org/GNOME/glib.git/': Empty reply from servererror: execv(/usr/bin/git clone https://gitlab.gnome.org/GNOME/glib.git -b 2.84.1 --depth 1 --recursive --shallow-submodules -c core.fsmonitor=false source.tmp/glib) failed(128), unknown reason => clone https://gitlab.gnome.org/GNOME/glib.git 2.84.1 .. failedwe can also download these packages manually: - https://gitlab.gnome.org/GNOME/glib.gitto the local search directories: - gliband we can run `xmake g --pkg_searchdirs=/xxx` to set the search directories.error:这个和国内访问GitHub不稳定有关系,一般重试xmake b -vy crossdesk几次可以解决。
可能还有其他报错:
meson.build:1:0: ERROR: Meson version is 0.53.2 but project requires >= 1.4.0A full log can be found at /home/lqf/.xmake/cache/packages/2603/g/glib/2.84.1/source/glib/build_a396b004/meson-logs/meson-log.txterror: execv(/usr/bin/meson setup -Dbsymbolic_functions=false -Ddtrace=false -Dman=false -Dgtk_doc=false -Dtests=false -Dinstalled_tests=false -Dsystemtap=false -Dselinux=disabled -Dlibmount=disabled -Dsysprof=disabled -Dglib_debug=disabled -Ddefault_library=static -Dgio_module_dir=/home/lqf/.xmake/packages/g/glib/2.84.1/4e0143c97b65425b855ad5fd03038b6a/lib/gio/modules --prefix=/home/lqf/.xmake/packages/g/glib/2.84.1/4e0143c97b65425b855ad5fd03038b6a --libdir=lib -Dbuildtype=release -Db_staticpic=true build_a396b004) failed(1), unknown reason => install glib 2.84.1 .. failed升级 Meson 到 1.4.0+。由于 Ubuntu 20.04 的 apt 源里 Meson 版本太旧,推荐用 pip 安装最新版:
# 1. 卸载系统自带的旧版 mesonsudo apt remove meson# 2. 用 pip3 安装最新版 meson(会装到 ~/.local/bin)pip3 install --user meson# 3. 确保 ~/.local/bin 在 PATH 中export PATH="$HOME/.local/bin:$PATH"# 4. 验证版本meson --version安装完成后,清理 xmake 的缓存再重新构建:
# 清理 glib 的缓存(避免用到旧的构建残留)xmake g --clean# 或者只清理 glib 包缓存rm -rf ~/.xmake/cache/packages/2603/g/glib# 重新构建cd ~/crossdeck-hub/crossdeskxmake b -vy crossdesk需要修改web_client.js 里signalingUrl和iceServers的地址:
const DEFAULT_CONFIG = { signalingUrl: "wss://api.crossdesk.cn:9099", iceServers: [ { urls: ["stun:api.crossdesk.cn:3478"] }, { urls: ["turn:api.crossdesk.cn:3478"], username: "crossdesk", credential: "crossdeskpw" }, ], heartbeatIntervalMs: 3000, heartbeatTimeoutMs: 10000, reconnectDelayMs: 2000, clientTag: "web",};改成自己的signalingUrl和iceServers的地址,iceServers还需要修改username和credential。比如我后续用:username:"lqf", credential:"123456".
启动
sudo nohup turnserver -L 0.0.0.0 --min-port 30000 --max-port 60000 -a -u lqf:123456 -v -f -r nort.gov &这里用户名设置为:lqf, 密码:123456。
以下提供三个版本:完整版(适合项目经验详写)、精简版(适合一页简历)、高级版(突出架构设计能力)。根据投递岗位侧重点选用。
项目角色:核心开发 |项目周期:202X.XX — 至今 |技术栈:C++17/WebRTC/SDL3/ImGui
项目简介:CrossDesk是一款跨平台(Windows/macOS/Linux/Web)远程桌面软件,支持屏幕共享、远程控制、文件传输、剪贴板同步等功能。系统由桌面客户端、信令服务器、Web客户端三部分组成,采用WebRTC实现低延迟P2P音视频传输。
系统架构:
桌面客户端(C++17):基于SDL3+ImGui构建跨平台GUI,集成自研WebRTC引擎minirtc,支持屏幕采集、音频采集、远程输入注入、文件传输
信令服务器(C++17):基于websocketpp实现TLS WebSocket服务,SQLite存储设备注册信息,负责信令路由与会话管理
Web客户端(JavaScript):基于浏览器原生WebRTC API,支持桌面端Pointer Lock和移动端虚拟触控
核心工作与技术亮点:
自研轻量级WebRTC引擎(minirtc)
基于libnice实现ICE协商与NAT穿透(P2P直连+TURN中继),支持STUN绑定请求和TURN Allocate/Refresh全流程
实现完整的RTP/RTCP协议栈,包括RTP打包/解包、RTCP SR/RR/NACK/PLI反馈、Paced Sender平滑发送
集成SRTP加密传输(libsrtp),通过DTLS握手交换密钥,保障媒体流安全
实现OpenFEC前向纠错,在丢包环境下无需重传即可恢复数据,降低延迟抖动
基于libdatachannel实现可靠/不可靠DataChannel,用于鼠标键盘控制指令和文件传输
多编码器视频编码管线
支持H.264(OpenH264)和AV1(AOM/SVT-AV1)软编码,macOS集成VideoToolbox硬编码,Windows/Linux支持NVIDIA NVENC硬编码
实现自适应分辨率调节(Resolution Adapter),根据网络带宽和RTCP反馈动态调整编码分辨率和码率
解码端支持OpenH264、dav1d(AV1)、AOM、VideoToolbox、NVDEC多后端,自动选择最优解码器
跨平台屏幕采集
Linux:基于XShmGetImage实现零拷贝共享内存屏幕采集,配合libyuv进行BGRA→NV12色彩空间转换
Windows:实现DXGI Desktop Duplication(主)、Windows Graphics Capture(备)、GDI(兜底)三级采集策略
macOS:基于ScreenCaptureKit实现高性能屏幕采集,支持多显示器独立采集与切换
跨平台输入注入
Linux:通过XTest扩展注入鼠标移动/点击/滚轮事件,键盘事件通过XSendEvent注入,实现Web端JS KeyCode→Linux KeySym的完整映射表
Windows:使用SendInput API注入鼠标和键盘事件
macOS:通过CGEvent API实现输入注入
鼠标坐标采用归一化浮点数(0.0~1.0)传输,接收端根据实际分辨率还原绝对坐标,兼容多分辨率场景
信令服务器设计
基于websocketpp+Asio实现异步TLS WebSocket服务器,支持高并发连接
设计Transmission会话模型:一个Host(被控端)绑定多个Guest(观看端),支持动态加入/离开
实现设备认证机制:SHA256+随机Salt密码哈希,SQLite持久化存储
实现设备在线状态管理(Presence),支持订阅推送,客户端可实时感知对端上下线
后台活性检测线程,10秒无活动自动清理僵尸连接,防止资源泄漏
文件传输与剪贴板同步
基于WebRTC可靠DataChannel实现文件传输,支持拖拽发送、传输进度显示、传输速率统计
文件传输采用队列机制,支持多文件顺序传输,ACK确认保证可靠性
实现跨平台剪贴板读写(X11 Selection/Windows Clipboard/macOS NSPasteboard)
项目成果:
端到端延迟控制在XX ms以内(局域网P2P),支持1080p@30fps流畅远程桌面
支持Windows/macOS/Linux/Web四端互通
项目开源,GitHub Star XXX+
独立设计并实现跨平台远程桌面系统,包含桌面客户端(C++)、信令服务器(C++)、Web客户端(JS),支持Windows/macOS/Linux/Web四端互通
自研WebRTC引擎:基于libnice实现ICE/DTLS/SRTP协商,完整RTP/RTCP协议栈(含NACK/PLI/Paced Sender),OpenFEC前向纠错,DataChannel可靠传输
多编码器视频管线:支持H.264(OpenH264)/AV1(SVT-AV1,AOM,dav1d)软编码,集成VideoToolbox/NVENC硬编码加速,自适应码率与分辨率调节
跨平台屏幕采集:Linux XShmGetImage零拷贝采集+libyuv色彩转换,Windows DXGI/WGC/GDI三级策略,macOS ScreenCaptureKit
跨平台输入注入:XTest(Linux)/SendInput(Windows)/CGEvent(macOS),归一化坐标传输兼容多分辨率
信令服务器:websocketpp+TLS异步WebSocket,Transmission会话模型(1 Host:N Guest),SHA256+Salt设备认证,SQLite持久化,Presence在线状态推送
基于可靠DataChannel实现文件传输(拖拽发送、队列调度、ACK确认、速率统计)和剪贴板同步
项目角色:架构设计&核心开发 |技术栈:C++17/WebRTC/SDL3/ImGui/websocketpp
架构设计:
设计并实现了完整的远程桌面系统架构,采用信令-媒体分离的经典WebRTC架构:
客户端 ←──WebSocket(TLS)──→ 信令服务器 ←──WebSocket(TLS)──→ 客户端 │ │ └──────── WebRTC (ICE/DTLS/SRTP/RTP/DataChannel) ──────────┘ │ coturn (TURN中继)关键架构决策与技术深度:
自研WebRTC引擎而非集成libwebrtc
动机:Google libwebrtc体积庞大(编译产物>100MB)、构建复杂(需depot_tools+数小时编译)、API变动频繁
方案:自研minirtc,仅集成核心协议栈(ICE/DTLS/SRTP/RTP/RTCP/DataChannel),编译产物轻量,xmake一键构建
基于libnice实现ICE Agent,支持host/srflx/relay三类候选,完整实现ICE Connectivity Check和Nomination
RTP层实现Paced Sender平滑发送避免突发拥塞,RTCP实现NACK重传和PLI关键帧请求
集成OpenFEC(Reed-Solomon)前向纠错,在5%~15%丢包率下无需重传即可恢复,显著降低尾延迟
多策略屏幕采集框架
设计ScreenCapturer抽象接口,通过Factory模式按平台实例化具体实现
Windows实现三级降级策略:DXGI Desktop Duplication(GPU直采,最优)→WGC(UWP兼容)→GDI(兜底)
Linux采用XShmGetImage共享内存零拷贝采集,避免XGetImage的内存拷贝开销
采集帧通过libyuv进行BGRA→NV12转换后直接送入编码器,减少一次色彩空间转换
编解码器抽象与自适应码率
编码器/解码器通过抽象接口统一管理,运行时根据平台和硬件能力自动选择最优编解码器
支持H.264和AV1双编码格式,AV1在同等画质下码率降低30%~50%,适合低带宽场景
基于RTCP Receiver Report的丢包率和RTT反馈,动态调整编码码率和分辨率(Resolution Adapter)
信令服务器的会话模型
设计Transmission抽象:一个Host绑定一个transmission_id(即设备ID),多个Guest可加入同一transmission
信令消息按类型路由:offer/answer/ICE点对点转发,join/leave广播通知
Presence机制:设备上下线事件推送给订阅者,客户端无需轮询即可感知对端状态
10秒活性检测+自动清理,防止WebSocket连接泄漏
跨平台工程实践
采用xmake构建系统统一管理C++17项目,一套xmake.lua支持Windows/macOS/Linux三平台编译
平台相关代码(屏幕采集、音频采集、输入注入)通过抽象接口+平台子目录隔离,新平台只需实现接口
GUI层采用SDL3(跨平台窗口/渲染)+ImGui(即时模式GUI),避免Qt的重量级依赖
微信扫一扫关注该公众号
继续滑动看下一个