摘要
本文从一个开源项目的真实实现出发,拆解 Qt 6 + C++17 如何实现 SFTP 批量部署 :面向 PLC 设备、Linux 工控机、云服务器的工业设备运维工具 DeviceForge,在 v2.6 版本用 IDeployable 接口把 FTP 与 SFTP 的批量部署做成了同一套部署循环,协议无关、一键切换。
如果你正打算给自研的工业运维工具补 SFTP 部署能力,或者好奇「批量部署」这类功能怎么设计才不把代码写死,这篇实战解析值得读完。

什么是 SFTP 批量部署
先对齐概念。SFTP(SSH File Transfer Protocol)是建立在 SSH 安全通道之上的文件传输协议,与 FTP 的最大区别是全程加密,且复用 SSH 的 22 端口------很多设备默认只开 SSH,不开 FTP 服务。
批量部署指的不是传单个文件,而是:
- 把一个固件包/程序文件夹递归上传到一台或多台设备
- 上传前可以清空目标目录(保留目录本身)
- 传输过程有进度、可取消
- 多台设备逐台执行,失败隔离------坏一台不影响其余设备
为什么用 SFTP 不用 FTP
这是 v2.6 版本最直接的推动力。v2.5 时工具的 SFTP 只支持「浏览和管理文件」,批量部署必须切回 FTP。但这个边界在实际使用中越来越撑不住:
- 标准 Linux 服务器、Ubuntu 工控机上,FTP 服务默认没开,SSH 反而是标配
- 部分支持 SSH 的新设备压根不提供 FTP 服务
- 云服务器运维场景里,安全组经常只放行 22 端口
单传一个文件还能绕(右键下载再拖上传),批量部署固件就绕不过去了。结论很明确:SFTP 必须成为与 FTP 对等的完整部署通道,而不是「能浏览不能部署」的半成品。
DeviceForge 是什么
DeviceForge(前身 DeployMaster)是一个基于 Qt 6 + C++17 的 Windows 桌面应用,面向工业硬件做「部署 → 测试 → 运维」:
- FTP/SFTP 批量部署固件
- Telnet/SSH 批量执行命令
- Modbus 寄存器读写
- OPC UA 客户端
- WebSocket 通信
- TCP/UDP 网络调试中继
开源项目,GitHub:turnarond/DeviceForge
v2.4 把 FTP 部署从表单改成了双栏文件管理器;v2.5 补完远程文件管理并做了 SylixOS 深度适配;v2.6 把 SFTP 从「单文件传输」变成「完整部署通道」。
Qt 6 怎么实现:IDeployable 接口抽象
这是 v2.6 最核心的技术设计。做法是不往 IProtocolAdapter 塞部署方法 ,而是新增一个可选能力接口 IDeployable(src/adapter/IDeployable.h):
cpp
class IDeployable {
public:
virtual ~IDeployable() = default;
// 上传单个文件到远程路径(remotePath 含文件名)
virtual bool uploadFile(const std::string& localPath, const std::string& remotePath) = 0;
// 递归上传整个目录(目录本身作为远程子目录创建)
virtual bool uploadFolder(const std::string& localPath, const std::string& remotePath) = 0;
// 清空远程目录内容(保留目录本身)
virtual bool clearRemoteDirectory(const std::string& remotePath) = 0;
// 进度回调:0-100 整数百分比
virtual void setProgressCallback(std::function<void(int)> cb) = 0;
// 取消标志:传输应在每文件/每块前检查并中止
virtual void setCancelFlag(std::atomic<bool>* flag) = 0;
};
(方法签名以仓库 src/adapter/IDeployable.h 为准)
FtpAdapter 和 SshAdapter 都实现这个接口;部署循环(FtpDeployBackend::startUpload)通过 dynamic_cast 探测------适配器支持部署能力就能进批量部署,与具体协议无关。
这个设计有三个好处:
- 映射成本最低 :FTP 已有的方法签名天然对齐(
clearRemoteDirectory、setCancelFlag等),SshAdapter 复用同样语义 - 新协议接入零改动 :未来如 SCP,只要实现
IDeployable就能获得整套批量部署能力,部署循环一行不改 - 能力可选 :不支持部署的协议适配器照常存在,
dynamic_cast返回空指针即可优雅降级
递归 mkdir 上传与清空语义
SshAdapter 的三个 SFTP 部署方法,细节都在边界里:
sftpUploadFolder:先用planFolderUpload递归遍历生成上传计划------目录项在前、文件项在后 ,保证 mkdir 先于文件上传;再逐项执行:目录mkdir(已存在 EEXIST 忽略,真失败由后续文件上传暴露),文件走sftpUploadFile(每项前检查取消标志)sftpClearDirectory:清空内容、保留目录本身 ------与 FTPclearRemoteDirectory语义对齐(直接递归删目录会导致后续上传失败)sftpSetCancelFlag:取消标志挂载,取消后每文件/每块前检查并中止
协议复用:SFTP 走「ssh」注册键
SFTP 部署复用 ssh 协议通道 ------ProtocolRegistry 注册键 "ssh" 的同一 SshAdapter 实现,不新建 sftp 工厂。FtpDeployWidget::currentProtocol() 对 SFTP 返回 "ssh",部署循环直接按该键取适配器。浏览与部署共用同一 SFTP 能力;部署时每设备独立连接(部署循环逐台 create("ssh") 新建适配器实例)。
部署循环与多设备支持
Tool = ToolBackend (ServiceTask) + ToolWidget (QWidget)
↕ lwmsgq 消息队列解耦
统一 IProtocolAdapter 接口 + ProtocolRegistry 工厂
↕ 可选部署能力:IDeployable(dynamic_cast 探测)
FtpAdapter / SshAdapter 均实现 → FtpDeployBackend 部署循环与协议无关
部署循环一次操作覆盖多台设备:逐台执行「连接 → 可选清空 → 上传 → 断开」,进度实时更新、可随时取消,失败设备自动收集跳过、其余设备不受影响。
双栏 UI 与 TC 化体验
v2.6 的双栏文件管理器也完成了 TC 化(Total Commander 风格):统一表格视图、面板顶部路径栏(Enter 跳转)、底部面包屑,快捷键 F2 重命名 / F5 复制到对面 / F6 移动到对面 / Tab 切栏 ;面板间拖拽走部署通道------把文件从左边本地面板拖到右边远程面板即触发上传,拖回即下载,跨面板方向语义清晰(系统文件拖入已移除,仅支持面板间拖拽)。部署目标目录 = 右侧面板当前路径,先导航再部署。
测试验证:11 个测试目标全过
v2.6 新增两个 QtTest 目标,加上既有目标,11 个测试目标全部通过:
| 目标 | 用例 | 覆盖 |
|---|---|---|
tst_sftp_plan |
3 个(plan_singleFile / plan_nestedDir / plan_emptyDir) |
上传计划生成:单文件、嵌套目录排序、空目录边界 |
tst_deploy_loop |
3 个(deploy_twoDevices_allSuccess / deploy_connectFail_deviceSkipped / deploy_cancelStopsRemaining) |
部署循环:多设备全成功、连接失败设备跳过、取消中止剩余 |
(另有 tst_remote_model、tst_theme、tst_file_source 等既有目标回归全过,CI 在 GitHub Actions 上跑 CMake + CTest)
诚实的限制
- SCP 未做 (v2.7 候选):
IDeployable接口已就位,SCP 只需实现接口 + 注册协议键即可获得整套部署能力 - 无断点续传:传输中断需重新部署
- 密钥认证待后续:SFTP 部署目前用账号密码认证(与浏览路径一致),SSH 私钥登录未接通
总结
v2.6 不是新功能堆叠,而是把最后一个传输缺口补上:
- SFTP 批量部署与 FTP 完全对等------同一双栏 UI 一键切换(FTP/SFTP 协议下拉),不用再为不同设备切换工具
- IDeployable 接口抽象------部署能力与协议解耦,SCP 等新协议接入成本降到最低
- 递归 mkdir 上传 + 清空保留目录 + 取消------语义与 FTP 对齐,行为可预期
配套的还有暗/亮双主题(设置中切换)、状态栏快捷键提示、部署方向指示等体验细节。
如果你也经常给 PLC 设备、Linux 工控机、云服务器批量传固件------FTP 和 SFTP 混着用的场景,这一版值得试试。
GitHub 开源地址 :turnarond/DeviceForge(欢迎 star / issue / PR)
作者简介
turnarond,工业软件开发者,专注设备运维工具链(Qt / C++ / 工业协议)。持续分享 DeployMaster → DeviceForge 从单体架构到服务核 + Qt 壳双层架构的实战改造过程。关注本专栏,下一篇拆解 IFileSource 文件源抽象与双栏面板模块化。
作者:turnarond | 2026-08-13