Files
SimpleRemoter/docs/FileTransferSpeed_Design.md
T
yuanyuanxianganddeepseek-v4-pro 76decec0fe Feature: Add file-transfer speed dialog with multi-language support
Add a novice-friendly "File Transfer Speed" dialog under the Advanced menu
that controls file-transfer speed in both directions without touching
SimplePlugins. Speed is passed through InitFileUpload's existing
chunkSizeKb/sendDurationMs arguments, so the precompiled library stays
untouched. Seven presets run from ~0.3 MB/s up to a new 10 MB/s tier plus an
unlimited tier; the chosen value is stored in [transfer] ChunkKb/DurationMs.

Upload reads THIS_CFG at the master's InitFileUpload (2015RemoteDlg.cpp:2225)
and takes effect on restart. Download is pushed to the client over a new
CMD_FILE_SPEED (252) command, sent from OnOnlineFileManager and
OnOnlineDesktopManager before each session opens, and read by all four client
InitFileUpload call sites via GetTransferSpeed so the process-global refcount
cannot latch a stale speed. All Chinese strings go through LangManager, with
en_US/zh_TW/de_DE entries added for the tier names, format strings and hint
text.

Co-Authored-By: deepseek-v4-pro
2026-10-02 19:57:57 +02:00

9.4 KiB
Raw Permalink Blame History

YAMA 文件传输速度调节设计

状态:已实现(Windows 端,含多语言)。其他平台(Linux/macOS 客户端)暂不实施。 读者:研发/评审人员。 关联文档:FILE_TRANSFER_V2.md(V2 协议)、Mcp_FileTransfer_Design.md(MCP 文件传输)。


1. 背景与目标

文件传输速度目前是写死的:SimplePlugins 库的 InitFileUpload(key, msg, hmac, chunkSizeKb, sendDurationMs, ...) 被 YAMA 所有调用点传 64, 50,折算 ≈ 1.25 MB/s。用户无法调节。

目标:在 YAMA 主菜单「高级」下新增一个面向小白的「文件传输速度」对话框——拖动滑块即完成设置,实时显示预估速度;不修改 SimplePlugins 库(库已编译,只通过其已暴露的 chunkSizeKb/sendDurationMs 两个入参控制)。


2. 速度原理(现状)

库内部把两个入参转成全局量(SimplePlugins/file_upload.cpp:221-222, 849-850):

static int chunk_size   = 64 * 1024;  // 默认 64KB
static int send_duration = 50;        // 默认 50ms
// InitFileUpload:  chunk_size = chunkSizeKb * 1024;  send_duration = sendDurationMs;

发送循环每发一块就 Sleep(send_duration)(V1 FileBatchTransferWorker 与 V2 FileBatchTransferWorkerV2 共用这对全局量):

预估速度 = chunkSizeKb * 1024 / (sendDurationMs / 1000) 字节/秒
默认 64KB / 50ms ≈ 1.25 MB/s

两个关键约束:

  1. 速度只在 InitFileUpload 时设定一次,库无运行时 setter(g_threadCount > 1 时提前返回,不会重设)。
  2. V1 / V2 共用同一对全局量,一次设置同时覆盖 COMMAND_SEND_FILE(68) 与 COMMAND_SEND_FILE_V2(85) 两种协议。

3. 档位表(权威唯一来源,主控端对话框维护)

档位 名称 chunkKb durationMs 预估速度
0 最慢 64 200 ≈ 0.3 MB/s
1 慢 64 100 ≈ 0.6 MB/s
2 默认 64 50 ≈ 1.25 MB/s
3 快 128 50 ≈ 2.5 MB/s
4 更快 256 50 ≈ 5 MB/s
5 很快 512 50 ≈ 10 MB/s
6 不限速 1024 0 网络上限
  • 滑块 CSliderCtrl 范围 0..6,SetPageSize(1),默认落在 2。
  • durationMs = 0 表示不人为限速(Sleep(0) 仅让出时间片,实际受带宽约束)。
  • 注意 Windows Sleep 粒度 ≈ 15.6ms:durationMs 低于约 15ms 基本等同不限速。故档位要么 ≥ 20ms,要么直接 0ms,不设 5ms 之类的“名不副实”中间值。

预估文案:当前约 1.25 MB/s;durationMs==0 显示 不限速(受网络带宽约束)。

  • 多语言:档位名(最慢/慢/默认/快/更快/很快/不限速)与预估格式串(%s · 约 %.2f MB/s、%s · 不受限速(受网络带宽约束))经 _TR/_LF 走 LangManager 翻译表;语言文件以中文原文为 key。刻度标签拆成 最慢/默认/不限速 三个独立 LTEXT 以便各自翻译(英文宽度不同,不能靠空格对齐)。

4. 两个方向的生效链路

文件传输有两条方向,InitFileUpload 各自在不同进程/时机调用:

方向 发送方 InitFileUpload 调用点 生效方式
上传(主控端 → 被控端) 主控端 server/2015Remote/2015RemoteDlg.cpp:2223(启动一次) 读 THIS_CFG,重启主控端生效
下载(被控端 → 主控端) 被控端 client/FileManager.cpp:40(CFileManager 构造,每会话一次) 读客户端配置,下次打开文件管理会话生效

4.1 上传方向(主控端本地,无协议改动)

2015RemoteDlg.cpp:2223 现为 InitFileUpload({},{},GetHMAC(),64,50,Logf,GetUpperHash()),改为读 THIS_CFG:

int chunkKb = THIS_CFG.GetInt("transfer", "ChunkKb", 64);
int durMs   = THIS_CFG.GetInt("transfer", "DurationMs", 50);
InitFileUpload({}, {}, GetHMAC(), chunkKb, durMs, Logf, GetUpperHash());

4.2 下载方向(需下发到被控端)

新增命令 CMD_FILE_SPEED,照 CMD_QUALITY_LEVEL(78) 的“服务端下发 → 客户端持久化 → 本地生效”套路:

  1. common/commands.h:新增 CMD_FILE_SPEED = 252(命令号单字节,252 < 255 安全)。
  2. 命令格式:[cmd:1][chunkKb:uint16 LE][durationMs:uint16 LE],共 5 字节。
    • 传原始 chunkKb/durationMs 而非档位索引,避免客户端复制映射表,映射表只存在于主控端对话框。
  3. 主控端下发:在 OnOnlineFileManager()(server/2015Remote/2015RemoteDlg.cpp:4737,发 COMMAND_LIST_DRIVE 开文件管理会话)发 COMMAND_LIST_DRIVE 之前,先经主连接把当前档位 CMD_FILE_SPEED(5 字节)发给被控端;OnOnlineDesktopManager()(2015RemoteDlg.cpp:4723,发 COMMAND_SCREEN_SPY)同理也发一次,覆盖“先开远程桌面再开文件管理”的引用计数时序。两处都在 SendFileSpeedCommand()(:9310)统一读取并下发。
  4. 被控端接收:在客户端主连接分发 client/KernelManager.cpp:814 的 switch(COMMAND_LIST_DRIVE 所在,case 加在 1280 附近)加 case CMD_FILE_SPEED,把两数写入 iniFile cfg(CLIENT_PATH) 的 [transfer] 节。
  5. 被控端调用点读配置:client/FileManager.cpp:40(CFileManager 构造)改为读 cfg.GetInt("transfer","ChunkKb",64) / DurationMs,替换硬编码 64, 50。CFileManager 每会话重建(构造 Init、析构 Uninit),故下次打开文件管理即生效。

关键:库用进程级引用计数,速度只在首次 InitFileUpload 时设定(g_threadCount > 1 时提前返回,不重设)。客户端共 4 个 InitFileUpload 调用点(FileManager.cpp:40、ScreenManager.cpp:109、ScreenManager.cpp:873、KernelManager.cpp:1399),谁先初始化谁锁定速度。故这 4 处必须全部改为读同一配置,否则下载速度会被先初始化的管理器(如远程桌面会话)锁成旧值。


5. 配置存储

  • 主控端:THIS_CFG(ini)[transfer] 节 ChunkKb / DurationMs(int)。
  • 被控端:iniFile(CLIENT_PATH) 的 [transfer] 节 ChunkKb / DurationMs(int),由 CMD_FILE_SPEED 写入。

存 ChunkKb/DurationMs 两个 int 而非档位索引:自解释、直接对应 InitFileUpload 入参、不易错位。


6. 改动文件清单(Windows 端)

文件 改动
server/2015Remote/resource.h 加 IDD_FILE_SPEED、ID_TOOL_FILE_SPEED、IDC_FSPEED_SLIDER、IDC_FSPEED_LABEL、IDC_FSPEED_RESET
server/2015Remote/2015Remote.rc 「高级」菜单加一项;新增对话框资源(滑块+预估标签+按钮)。文件为 UTF-16LE 编码,须按 Unicode 读写
server/2015Remote/CFileSpeedDlg.h 新建:档位表 + OnHScroll 实时预估 + 恢复默认(照 CPreviewLevelsDlg.h 内联实现)
server/2015Remote/2015RemoteDlg.h 加 OnFileTransferSpeed() 声明
server/2015Remote/2015RemoteDlg.cpp 消息映射 ON_COMMAND(ID_TOOL_FILE_SPEED, ...);2223 读配置(上传);OnFileTransferSpeed() 弹出对话框并写回 THIS_CFG;OnOnlineFileManager()/OnOnlineDesktopManager() 发 CMD_FILE_SPEED
common/commands.h 加 CMD_FILE_SPEED = 252
client/KernelManager.cpp case CMD_FILE_SPEED 写客户端配置(主连接 switch,814)
client/FileManager.cpp、client/ScreenManager.cpp、client/KernelManager.cpp 4 个 InitFileUpload 调用点读配置替换硬编码 64, 50(引用计数要求全部一致)
server/2015Remote/lang/en_US.ini、zh_TW.ini、de_DE.ini 追加「文件传输速度」相关 13 条中文原文→译文(GBK 编码,RCDATA "lang\*.ini" 由 rc.exe 嵌入)

7. 生效时机与提示文案

  • 上传速度:重启主控端生效。
  • 下载速度:下次打开该主机的文件管理会话生效。
  • 对话框保存后弹提示:文件传输速度已保存。上传速度重启主控端后生效;下载速度下次打开文件管理或远程桌面后生效。

8. 风险与备注

  1. Sleep 精度:Windows 计时器粒度约 15.6ms,durationMs 过小则失真(见 §3)。
  2. 实际速度 < 预估:预估为纯 chunk/delay 理论值,未计入 f() 网络发送耗时;对话框文案用“约/大概”表述。
  3. 命令号冲突:CMD_FILE_SPEED=252 需确认 commands.h 无重号;252 < 255(单字节 uint8_t cmd 上限)。
  4. .rc 编码:2015Remote.rc 为 UTF-16LE(带 BOM),编辑必须按 Unicode 处理,避免破坏资源脚本。
  5. 跨平台:Linux/macOS 客户端下载路径暂不改(CMD_FILE_SPEED 会被老/其他平台客户端静默忽略,向后兼容)。
  6. 多语言 key 精确匹配:语言文件为 GBK 编码、key 不 trim(CIniParser 保留原始空格);译文 key 必须与源码逐字一致——源码为 UTF-8、经 /execution-charset:.936 编译为 GBK,·(U+00B7)、全角括号()等需一致,否则查不到翻译。

9. 实施顺序

  1. common/commands.h 加命令号 → resource.h 加 ID → .rc 加菜单项与对话框资源。
  2. 新建 CFileSpeedDlg.h → 2015RemoteDlg 接线(上传方向,可先验证)。
  3. 主控端下发 CMD_FILE_SPEED → 客户端接收持久化 → 客户端调用点读配置(下载方向)。
  4. 编译验证(MSBuild 须传 -p:SolutionDir,见项目记忆)。