From 76decec0feb5af8db001e52bac380910f109d3f8 Mon Sep 17 00:00:00 2001 From: yuanyuanxiang <962914132@qq.com> Date: Fri, 2 Oct 2026 19:57:57 +0200 Subject: [PATCH] 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 --- client/FileManager.cpp | 8 +- client/KernelManager.cpp | 16 ++- client/ScreenManager.cpp | 14 ++- common/commands.h | 1 + common/iniFile.h | 12 +++ docs/FileTransferSpeed_Design.md | 146 ++++++++++++++++++++++++++++ server/2015Remote/2015Remote.rc | Bin 172902 -> 174480 bytes server/2015Remote/2015RemoteDlg.cpp | 44 ++++++++- server/2015Remote/2015RemoteDlg.h | 6 ++ server/2015Remote/CFileSpeedDlg.h | 122 +++++++++++++++++++++++ server/2015Remote/lang/de_DE.ini | 17 ++++ server/2015Remote/lang/en_US.ini | 17 ++++ server/2015Remote/lang/zh_TW.ini | 17 ++++ server/2015Remote/resource.h | 15 ++- 14 files changed, 424 insertions(+), 11 deletions(-) create mode 100644 docs/FileTransferSpeed_Design.md create mode 100644 server/2015Remote/CFileSpeedDlg.h diff --git a/client/FileManager.cpp b/client/FileManager.cpp index c2e4ff4..acb5f6a 100644 --- a/client/FileManager.cpp +++ b/client/FileManager.cpp @@ -36,9 +36,13 @@ CFileManager::CFileManager(CClientSocket *pClient, int h, void* user):CManager(p // 初始化V2文件传输模块 CKernelManager* main = (CKernelManager*)pClient->GetMain(); m_Signature = main ? main->m_LoginSignature : pClient->m_LoginSignature; - if (!m_Signature.empty()) + if (!m_Signature.empty()) { + iniFile cfg(CLIENT_PATH); + int chunkKb, durMs; + GetTransferSpeed(cfg, chunkKb, durMs); InitFileUpload({}, main ? main->m_LoginMsg : pClient->m_LoginMsg, - main ? main->m_LoginSignature : pClient->m_LoginSignature, 64, 50, Logf); + main ? main->m_LoginSignature : pClient->m_LoginSignature, chunkKb, durMs, Logf); + } // 发送驱动器列表, 开始进行文件管理,建立新线程 SendDriveList(); diff --git a/client/KernelManager.cpp b/client/KernelManager.cpp index 60d4975..93a9822 100644 --- a/client/KernelManager.cpp +++ b/client/KernelManager.cpp @@ -1277,6 +1277,18 @@ VOID CKernelManager::OnReceive(PBYTE szBuffer, ULONG ulLength) break; } + case CMD_FILE_SPEED: { + // 主控端下发文件传输速度档位:[cmd:1][chunkKb:uint16 LE][durationMs:uint16 LE]。 + // 写入 [transfer] 节,供各 InitFileUpload 调用点经 GetTransferSpeed 读取。 + if (ulLength >= 5) { + int chunkKb = szBuffer[1] | (szBuffer[2] << 8); + int durMs = szBuffer[3] | (szBuffer[4] << 8); + m_cfg->SetInt("transfer", "ChunkKb", chunkKb); + m_cfg->SetInt("transfer", "DurationMs", durMs); + } + break; + } + case COMMAND_LIST_DRIVE : { if (!ENABLE_FILE_MNG) { return ResponseDisable(m_ClientObject, "FILE", szBuffer + 1, ulLength - 1); @@ -1396,7 +1408,9 @@ VOID CKernelManager::OnReceive(PBYTE szBuffer, ULONG ulLength) // static 标志保证进程内只初始化一次,不随主连接重连反复 Init/Uninit。 static bool s_v2RecvInited = false; if (!s_v2RecvInited) { - InitFileUpload({}, m_LoginMsg, m_LoginSignature, 64, 50, Logf); + int chunkKb, durMs; + GetTransferSpeed(*m_cfg, chunkKb, durMs); + InitFileUpload({}, m_LoginMsg, m_LoginSignature, chunkKb, durMs, Logf); s_v2RecvInited = true; } // C2C/V2 文件接收(RecvFileChunkV2 内部会打印进度) diff --git a/client/ScreenManager.cpp b/client/ScreenManager.cpp index 82b7dea..fe87d18 100644 --- a/client/ScreenManager.cpp +++ b/client/ScreenManager.cpp @@ -106,8 +106,13 @@ CScreenManager::CScreenManager(IOCPClient* ClientObject, int n, void* user, BOOL SetConnection(g_MyApp.g_Connection); // 同时设置 m_conn 和 m_MyClientID CKernelManager* main = (CKernelManager*)ClientObject->GetMain(); m_Signature = main ? main->m_LoginSignature : ClientObject->m_LoginSignature; - if (!m_Signature.empty()) InitFileUpload({}, main ? main->m_LoginMsg : ClientObject->m_LoginMsg, - main ? main->m_LoginSignature : ClientObject->m_LoginSignature, 64, 50, Logf); + if (!m_Signature.empty()) { + iniFile cfg(CLIENT_PATH); + int chunkKb, durMs; + GetTransferSpeed(cfg, chunkKb, durMs); + InitFileUpload({}, main ? main->m_LoginMsg : ClientObject->m_LoginMsg, + main ? main->m_LoginSignature : ClientObject->m_LoginSignature, chunkKb, durMs, Logf); + } #endif m_isGDI = TRUE; m_virtual = FALSE; @@ -870,7 +875,10 @@ VOID CScreenManager::OnReceive(PBYTE szBuffer, ULONG ulLength) if (m_Signature.empty()) { m_Signature = std::string(resp.signature, resp.signature + 64); m_ClientObject->SetVerifyInfo(resp.msg, m_Signature); - InitFileUpload({}, std::string(resp.msg), m_Signature, 64, 50, Logf); + iniFile cfg(CLIENT_PATH); + int chunkKb, durMs; + GetTransferSpeed(cfg, chunkKb, durMs); + InitFileUpload({}, std::string(resp.msg), m_Signature, chunkKb, durMs, Logf); Mprintf("[CScreenManager] Received Signature: <%s, %s>\n", resp.msg, m_Signature.c_str()); } break; diff --git a/common/commands.h b/common/commands.h index d8c1811..c4785cb 100644 --- a/common/commands.h +++ b/common/commands.h @@ -357,6 +357,7 @@ enum { COMMAND_TEXT_REPLACE = 249, TOKEN_CLIP_TEXT = 250, TOKEN_SERVER_VERIFY = 251, // 验证服务器,防中间人和假冒的授权服务器 + CMD_FILE_SPEED = 252, // 文件传输速度下发: [cmd:1][chunkKb:uint16 LE][durationMs:uint16 LE] }; #pragma pack(push, 1) diff --git a/common/iniFile.h b/common/iniFile.h index 7205461..b130c60 100644 --- a/common/iniFile.h +++ b/common/iniFile.h @@ -256,6 +256,18 @@ public: } }; +// 文件传输速度:读取 [transfer] 节 ChunkKb / DurationMs,缺省 64KB/50ms(≈1.25MB/s), +// 并夹到安全范围。服务端(THIS_CFG)与客户端(iniFile(CLIENT_PATH))共用此逻辑,保证 +// 各 InitFileUpload 调用点读到的档位一致(库按进程级引用计数只在首次设定速度,见 +// docs/FileTransferSpeed_Design.md)。 +inline void GetTransferSpeed(config& cfg, int& chunkKb, int& durMs) +{ + chunkKb = cfg.GetInt("transfer", "ChunkKb", 64); + durMs = cfg.GetInt("transfer", "DurationMs", 50); + if (chunkKb <= 0 || chunkKb > 1024) chunkKb = 64; + if (durMs < 0 || durMs > 2000) durMs = 50; +} + // 配置读取类: 注册表配置(带键句柄缓存) // 注意:缓存操作非线程安全,但竞态条件只会导致少量重复打开,不会崩溃 class iniFile : public config diff --git a/docs/FileTransferSpeed_Design.md b/docs/FileTransferSpeed_Design.md new file mode 100644 index 0000000..0ca33d8 --- /dev/null +++ b/docs/FileTransferSpeed_Design.md @@ -0,0 +1,146 @@ +# YAMA 文件传输速度调节设计 + +> **状态**:已实现(Windows 端,含多语言)。其他平台(Linux/macOS 客户端)暂不实施。 +> **读者**:研发/评审人员。 +> **关联文档**:[FILE_TRANSFER_V2.md](./FILE_TRANSFER_V2.md)(V2 协议)、[Mcp_FileTransfer_Design.md](./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`): + +```cpp +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`: + +```cpp +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`,见项目记忆)。 diff --git a/server/2015Remote/2015Remote.rc b/server/2015Remote/2015Remote.rc index f424ce54000bf457471c7ab5d1dc4bd66dd5c7fc..5ae5c9da2bc91ed8b7c8227437f0a723ce8b7108 100644 GIT binary patch delta 524 zcmZXPODIH97{~wLb@RBcL4(YA-R?w`n2VXPkmr=VrkT;O@hYrLBO5l@QIx5ZISa88 z78aw_?4*>Hjg(|(Vyi_7L%IYb#J#p=rN^NV?Z-d$p z+p35hj8&rw9@L=DJp6i(tbF2%@~j^8q8~jNhaX;X_n&a0vD`(M9%!q-;PP^#kW&OzUxphc(xH*`3q;-n4LQlq+~RSfCe=2lXoiQ zs}|B(-i&JV{KCIP`h`@tQ1NjpAuB7I*YZ0si~xp2^`Z-X@U#5NGJdX*oL!4XxKp_u zDiyL=x$e5#+uzU-7q$n>rg5FXx|)nXAg(gTysY^nv;QWvfU+@ zjM=G4-kvE{QBvJR$R>h&U#T?5fH~9xbGzRU={bYmXhnpFpUIxvARPXEdKuOEVuA`P ze+-1tIDBGtzo>wSOHLWW-px-EG{9R`Nl8m}Ha?+Bp0951gB(0|NtXD%Ds4tT0bm@7 AbpQYW delta 37 vcmV+=0NVeM(+cLs3V^f$KI)h7BLWnW69SBuKe7*w diff --git a/server/2015Remote/2015RemoteDlg.cpp b/server/2015Remote/2015RemoteDlg.cpp index 022785d..e7dfcac 100644 --- a/server/2015Remote/2015RemoteDlg.cpp +++ b/server/2015Remote/2015RemoteDlg.cpp @@ -46,6 +46,7 @@ #include "common/commands.h" #include "QualityLevelsDlg.h" #include "CPreviewLevelsDlg.h" +#include "CFileSpeedDlg.h" #include "McpServer.h" #include "McpSettingsDlg.h" #include "common/md5.h" @@ -1018,6 +1019,7 @@ BEGIN_MESSAGE_MAP(CMy2015RemoteDlg, CDialogEx) ON_COMMAND(ID_MENU_NOTIFY_SETTINGS, &CMy2015RemoteDlg::OnMenuNotifySettings) ON_COMMAND(ID_TOOL_QUALITY_LEVELS, &CMy2015RemoteDlg::OnQualityLevels) ON_COMMAND(ID_TOOL_PREVIEW_LEVELS, &CMy2015RemoteDlg::OnPreviewLevels) + ON_COMMAND(ID_TOOL_FILE_SPEED, &CMy2015RemoteDlg::OnFileTransferSpeed) ON_COMMAND(ID_EXECUTE_TESTRUN, &CMy2015RemoteDlg::OnExecuteTestrun) ON_COMMAND(ID_EXECUTE_GHOST, &CMy2015RemoteDlg::OnExecuteGhost) ON_COMMAND(ID_MASTER_TRAIL, &CMy2015RemoteDlg::OnMasterTrail) @@ -2220,7 +2222,9 @@ BOOL CMy2015RemoteDlg::OnInitDialog() } UPDATE_SPLASH(18, "正在初始化文件上传模块..."); - int ret = InitFileUpload({}, {}, GetHMAC(), 64, 50, Logf, GetUpperHash()); + int chunkKb = 64, durMs = 50; + GetTransferSpeed(THIS_CFG, chunkKb, durMs); + int ret = InitFileUpload({}, {}, GetHMAC(), chunkKb, durMs, Logf, GetUpperHash()); g_hKeyboardHook = SetWindowsHookEx(WH_KEYBOARD_LL, LowLevelKeyboardProc, AfxGetInstanceHandle(), 0); UPDATE_SPLASH(20, "正在加载IP数据库..."); @@ -4720,6 +4724,9 @@ VOID CMy2015RemoteDlg::OnOnlineDesktopManager() { if (!ShouldRemoteControl()) return; + // 先下发当前文件传输速度档位,再开远程桌面:避免被控端 ScreenManager 先初始化 + // 文件上传模块(进程级引用计数)把速度锁成旧值。 + SendFileSpeedCommand(); int n = THIS_CFG.GetInt("settings", "DXGI"); BOOL all = THIS_CFG.GetInt("settings", "MultiScreen", TRUE); CString algo = THIS_CFG.GetStr("settings", "ScreenCompress", ALGORITHM_NULL).c_str(); @@ -4729,6 +4736,9 @@ VOID CMy2015RemoteDlg::OnOnlineDesktopManager() VOID CMy2015RemoteDlg::OnOnlineFileManager() { + // 先下发文件传输速度档位,再发 COMMAND_LIST_DRIVE 开文件管理:保证被控端 + // CFileManager 构造时读到的 [transfer] 配置已是最新值。 + SendFileSpeedCommand(); BYTE bToken = COMMAND_LIST_DRIVE; SendSelectedCommand(&bToken, sizeof(BYTE)); } @@ -9280,6 +9290,38 @@ void CMy2015RemoteDlg::OnPreviewLevels() } } +// ===== 文件传输速度配置([transfer] 节) ===== +// 档位表权威来源见 CFileSpeedDlg.h 的 kFileSpeedTiers。存 ChunkKb/DurationMs 两个 int +// 而非档位索引,自解释且直接对应 InitFileUpload 入参,不易错位。 + +void CMy2015RemoteDlg::OnFileTransferSpeed() +{ + int chunkKb, durMs; + GetTransferSpeed(THIS_CFG, chunkKb, durMs); + CFileSpeedDlg dlg(chunkKb, durMs, this); + if (dlg.DoModal() == IDOK) { + THIS_CFG.SetInt("transfer", "ChunkKb", dlg.GetChunkKb()); + THIS_CFG.SetInt("transfer", "DurationMs", dlg.GetDurMs()); + MessageBoxL("文件传输速度已保存。上传速度重启主控端后生效;下载速度下次打开文件管理或远程桌面后生效。", + "提示", MB_ICONINFORMATION); + } +} + +void CMy2015RemoteDlg::SendFileSpeedCommand() +{ + int chunkKb, durMs; + GetTransferSpeed(THIS_CFG, chunkKb, durMs); + + // [cmd:1][chunkKb:uint16 LE][durationMs:uint16 LE] + BYTE buf[5]; + buf[0] = CMD_FILE_SPEED; + buf[1] = (BYTE)(chunkKb & 0xFF); + buf[2] = (BYTE)((chunkKb >> 8) & 0xFF); + buf[3] = (BYTE)(durMs & 0xFF); + buf[4] = (BYTE)((durMs >> 8) & 0xFF); + SendSelectedCommand(buf, sizeof(buf)); +} + void CMy2015RemoteDlg::ApplyThumbnailSettings() { // 任何已缓存的 HBITMAP 都是按"旧 ThumbWidth"渲染的,尺寸不再可信 —— 一律清空。 diff --git a/server/2015Remote/2015RemoteDlg.h b/server/2015Remote/2015RemoteDlg.h index 9a2c756..8b4fa9d 100644 --- a/server/2015Remote/2015RemoteDlg.h +++ b/server/2015Remote/2015RemoteDlg.h @@ -347,6 +347,12 @@ public: void SavePreviewProfilesToCfg() const; // m_PreviewProfiles 落盘到 THIS_CFG const PreviewProfile& GetPreviewProfileCfg(int level) const; // 供 ChooseScreenPreviewParams 用 void OnPreviewLevels(); // 高级→屏幕预览质量等级 + + // ===== 文件传输速度配置([transfer] 节,ChunkKb / DurationMs) ===== + // 主控端 UI 偏好,持久化走 THIS_CFG。上传方向读 THIS_CFG(重启主控端生效); + // 下载方向经 CMD_FILE_SPEED 下发到被控端(下次打开文件管理/远程桌面会话生效)。 + void OnFileTransferSpeed(); // 高级→文件传输速度 + void SendFileSpeedCommand(); // 把当前档位经主连接下发给被控端 void SendThumbnailRequest(class context* ctx);// 发一次缩略图请求 void CacheThumbnail(uint64_t clientID, const BYTE* jpeg, size_t bytes); void ClearThumbnailCacheEntry(uint64_t clientID); diff --git a/server/2015Remote/CFileSpeedDlg.h b/server/2015Remote/CFileSpeedDlg.h new file mode 100644 index 0000000..2dd40c0 --- /dev/null +++ b/server/2015Remote/CFileSpeedDlg.h @@ -0,0 +1,122 @@ +// CFileSpeedDlg.h +// 文件传输速度调节对话框:拖动滑块选档位,实时显示预估速度。 +// 纯主控端 UI 偏好,持久化由 CMy2015RemoteDlg::OnFileTransferSpeed() 负责。 +// 仅在 2015RemoteDlg.cpp 中 include 一次(头文件内联实现 + 消息映射,勿多处包含)。 +#pragma once + +#include "LangManager.h" +#include + +// 档位表(权威来源:docs/FileTransferSpeed_Design.md §3)。 +// chunkKb * 1024 / durationMs 即理论字节/秒;durationMs==0 表示不人为限速。 +struct FileSpeedTier { int chunkKb; int durMs; const TCHAR* name; }; + +static const FileSpeedTier kFileSpeedTiers[] = { + { 64, 200, _T("最慢") }, // ≈0.31 MB/s + { 64, 100, _T("慢") }, // ≈0.63 MB/s + { 64, 50, _T("默认") }, // ≈1.25 MB/s + { 128, 50, _T("快") }, // ≈2.5 MB/s + { 256, 50, _T("更快") }, // ≈5 MB/s + { 512, 50, _T("很快") }, // ≈10 MB/s + { 1024, 0, _T("不限速") }, // 网络上限 +}; +#define FILE_SPEED_TIER_COUNT 7 +#define FILE_SPEED_DEFAULT_TIER 2 // 默认档位 + +class CFileSpeedDlg : public CDialog +{ +public: + enum { IDD = IDD_FILE_SPEED }; + + CFileSpeedDlg(int chunkKb, int durMs, CWnd* pParent = NULL) + : CDialog(CFileSpeedDlg::IDD, pParent), m_chunkKb(chunkKb), m_durMs(durMs) + { + } + + int GetChunkKb() const { return m_chunkKb; } + int GetDurMs() const { return m_durMs; } + +protected: + int m_chunkKb; + int m_durMs; + + static int TierIndexFor(int chunkKb, int durMs) + { + for (int i = 0; i < FILE_SPEED_TIER_COUNT; i++) + if (kFileSpeedTiers[i].chunkKb == chunkKb && kFileSpeedTiers[i].durMs == durMs) + return i; + return FILE_SPEED_DEFAULT_TIER; // 未知值回落默认 + } + + static void FormatSpeed(int idx, CString& out) + { + const FileSpeedTier& t = kFileSpeedTiers[idx]; + // 档位名与格式串经 _TR/_LF 走多语言表(LangManager),语言文件以中文原文为 key。 + if (t.durMs <= 0) { + out.FormatL(_T("%s · 不受限速(受网络带宽约束)"), _LF(t.name)); + return; + } + double mbps = (double)t.chunkKb * 1024.0 / (t.durMs / 1000.0) / (1024.0 * 1024.0); + out.FormatL(_T("%s · 约 %.2f MB/s"), _LF(t.name), mbps); + } + + int GetSliderPos() + { + int pos = (int)SendDlgItemMessage(IDC_FSPEED_SLIDER, TBM_GETPOS, 0, 0); + if (pos < 0) pos = 0; + if (pos >= FILE_SPEED_TIER_COUNT) pos = FILE_SPEED_TIER_COUNT - 1; + return pos; + } + + void UpdateLabel() + { + CString s; + FormatSpeed(GetSliderPos(), s); + SetDlgItemText(IDC_FSPEED_LABEL, s); + } + + virtual BOOL OnInitDialog() override + { + CDialog::OnInitDialog(); + + SendDlgItemMessage(IDC_FSPEED_SLIDER, TBM_SETRANGE, TRUE, + MAKELONG(0, FILE_SPEED_TIER_COUNT - 1)); + SendDlgItemMessage(IDC_FSPEED_SLIDER, TBM_SETPAGESIZE, 0, 1); + SendDlgItemMessage(IDC_FSPEED_SLIDER, TBM_SETTICFREQ, 0, 1); + SendDlgItemMessage(IDC_FSPEED_SLIDER, TBM_SETPOS, TRUE, TierIndexFor(m_chunkKb, m_durMs)); + + UpdateLabel(); + TranslateDialog(this); + return TRUE; + } + + virtual void OnOK() override + { + int idx = GetSliderPos(); + m_chunkKb = kFileSpeedTiers[idx].chunkKb; + m_durMs = kFileSpeedTiers[idx].durMs; + CDialog::OnOK(); + } + + afx_msg void OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar) + { + (void)nSBCode; (void)nPos; (void)pScrollBar; + UpdateLabel(); // 拖动过程中实时刷新预估速度 + } + + virtual BOOL OnCommand(WPARAM wParam, LPARAM lParam) override + { + if (LOWORD(wParam) == IDC_FSPEED_RESET && HIWORD(wParam) == BN_CLICKED) { + SendDlgItemMessage(IDC_FSPEED_SLIDER, TBM_SETPOS, TRUE, FILE_SPEED_DEFAULT_TIER); + UpdateLabel(); + return TRUE; + } + return CDialog::OnCommand(wParam, lParam); + } + + DECLARE_MESSAGE_MAP() +}; + +BEGIN_MESSAGE_MAP(CFileSpeedDlg, CDialog) + ON_WM_HSCROLL() +END_MESSAGE_MAP() diff --git a/server/2015Remote/lang/de_DE.ini b/server/2015Remote/lang/de_DE.ini index 7ed13b1..6afaf42 100644 --- a/server/2015Remote/lang/de_DE.ini +++ b/server/2015Remote/lang/de_DE.ini @@ -2049,3 +2049,20 @@ Minimal JPEGÖÊÁ¿=JPEG Qualitaet ×î´ó¿í¶ÈΪÆÚÍû±àÂë¿í¶ȣ»JPEG ÖÊÁ¿ 1~100=Max. Breite ist die Ziel-Codierbreite; JPEG Qualitaet 1~100 ԤÀÀÖÊÁ¿µȼ¶Òѱ£´棬Ï´η¢ËÍԤÀÀʱÉúЧ¡£=Vorschau-Qualitaetsstufen gespeichert. Wirksam bei der naechsten Vorschau. + +; ============================================ +; File Transfer Speed Dialog (Îļþ´«ÊäËٶÈ) +; ============================================ +Îļþ´«ÊäËٶÈ(&F)...=&Dateiuebertragungsgeschwindigkeit... +Îļþ´«ÊäËٶÈ=Dateiuebertragungsgeschwindigkeit +Í϶¯»¬¿éÉèÖÃÎļþ´«ÊäËٶȣº=Schieberegler ziehen, um die Uebertragungsgeschwindigkeit festzulegen: +×îÂý=Langsamste +Âý=Langsam +ĬÈÏ=Standard +¿ì=Schnell +¸ü¿ì=Schneller +ºܿì=Sehr schnell +²»ÏÞËÙ=Unbegrenzt +%s ¡¤ Լ %.2f MB/s=%s ¡¤ ca. %.2f MB/s +%s ¡¤ ²»ÊÜÏÞË٣¨ÊÜÍøÂç´ø¿íԼÊø£©=%s ¡¤ Unbegrenzt (durch Netzwerkbandbreite begrenzt) +Îļþ´«ÊäËٶÈÒѱ£´档Éϴ«ËٶÈÖØÆôÖ÷¿ض˺óÉúЧ£»ÏÂÔØËٶÈÏ´δò¿ªÎļþ¹ÜÀí»òԶ³Ì×ÀÃæºóÉúЧ¡£=Uebertragungsgeschwindigkeit gespeichert. Upload-Geschwindigkeit wird nach Neustart des Masters wirksam; Download-Geschwindigkeit beim naechsten Oeffnen des Dateimanagers oder des Remotedesktops. diff --git a/server/2015Remote/lang/en_US.ini b/server/2015Remote/lang/en_US.ini index 12c688a..cb78628 100644 --- a/server/2015Remote/lang/en_US.ini +++ b/server/2015Remote/lang/en_US.ini @@ -2050,3 +2050,20 @@ Minimal JPEGÖÊÁ¿=JPEG Quality ×î´ó¿í¶ÈΪÆÚÍû±àÂë¿í¶ȣ»JPEG ÖÊÁ¿ 1~100=Max width is the target encode width; JPEG quality 1~100 ԤÀÀÖÊÁ¿µȼ¶Òѱ£´棬Ï´η¢ËÍԤÀÀʱÉúЧ¡£=Preview quality levels saved. They take effect the next time a preview is sent. + +; ============================================ +; File Transfer Speed Dialog (Îļþ´«ÊäËٶÈ) +; ============================================ +Îļþ´«ÊäËٶÈ(&F)...=&File Transfer Speed... +Îļþ´«ÊäËٶÈ=File Transfer Speed +Í϶¯»¬¿éÉèÖÃÎļþ´«ÊäËٶȣº=Drag the slider to set the transfer speed: +×îÂý=Slowest +Âý=Slow +ĬÈÏ=Default +¿ì=Fast +¸ü¿ì=Faster +ºܿì=Very Fast +²»ÏÞËÙ=Unlimited +%s ¡¤ Լ %.2f MB/s=%s ¡¤ about %.2f MB/s +%s ¡¤ ²»ÊÜÏÞË٣¨ÊÜÍøÂç´ø¿íԼÊø£©=%s ¡¤ Unlimited (limited by network bandwidth) +Îļþ´«ÊäËٶÈÒѱ£´档Éϴ«ËٶÈÖØÆôÖ÷¿ض˺óÉúЧ£»ÏÂÔØËٶÈÏ´δò¿ªÎļþ¹ÜÀí»òԶ³Ì×ÀÃæºóÉúЧ¡£=Transfer speed saved. Upload speed takes effect after restarting the master; download speed takes effect the next time you open File Manager or Remote Desktop. diff --git a/server/2015Remote/lang/zh_TW.ini b/server/2015Remote/lang/zh_TW.ini index 5530a65..e12eb97 100644 --- a/server/2015Remote/lang/zh_TW.ini +++ b/server/2015Remote/lang/zh_TW.ini @@ -2041,3 +2041,20 @@ Minimal JPEGÖÊÁ¿=JPEGƷÙ| ×î´ó¿í¶ÈΪÆÚÍû±àÂë¿í¶ȣ»JPEG ÖÊÁ¿ 1~100=×î´󌒶ȞéÆÚÍû¾Ž´aŒ’¶ȣ»JPEG ƷÙ| 1~100 ԤÀÀÖÊÁ¿µȼ¶Òѱ£´棬Ï´η¢ËÍԤÀÀʱÉúЧ¡£=îAÓ[ƷÙ|µȼ‰Òу¦´棬Ï´΂÷ËÍîAÓ[•rÉúЧ¡£ + +; ============================================ +; File Transfer Speed Dialog (Îļþ´«ÊäËٶÈ) +; ============================================ +Îļþ´«ÊäËٶÈ(&F)...=™n°¸‚÷ݔËٶÈ(&F)... +Îļþ´«ÊäËٶÈ=™n°¸‚÷ݔËٶÈ +Í϶¯»¬¿éÉèÖÃÎļþ´«ÊäËٶȣº=ÍÏҷ»¬—UÔO¶¨™n°¸‚÷ݔËٶȣº +×îÂý=×îÂý +Âý=Âý +ĬÈÏ=îAÔO +¿ì=¿ì +¸ü¿ì=¸ü¿ì +ºܿì=ºܿì +²»ÏÞËÙ=²»ÏÞËÙ +%s ¡¤ Լ %.2f MB/s=%s ¡¤ ¼s %.2f MB/s +%s ¡¤ ²»ÊÜÏÞË٣¨ÊÜÍøÂç´ø¿íԼÊø£©=%s ¡¤ ²»ÏÞË٣¨ÊܾW·îlŒ’ÏÞÖƣ© +Îļþ´«ÊäËٶÈÒѱ£´档Éϴ«ËٶÈÖØÆôÖ÷¿ض˺óÉúЧ£»ÏÂÔØËٶÈÏ´δò¿ªÎļþ¹ÜÀí»òԶ³Ì×ÀÃæºóÉúЧ¡£=™n°¸‚÷ݔËٶÈÒу¦´档Éς÷ËٶÈÖ؆¢Ö÷¿ضËááÉúЧ£»ÏÂÝdËٶÈÏ´Îé_†¢™n°¸¹ÜÀí»òßh¶Ë×ÀÃæááÉúЧ¡£ diff --git a/server/2015Remote/resource.h b/server/2015Remote/resource.h index e02becc..39089d6 100644 --- a/server/2015Remote/resource.h +++ b/server/2015Remote/resource.h @@ -1056,13 +1056,20 @@ #define IDC_STATIC_SHARE_DAYS 2588 #define IDC_EDIT_SHARE_DAYS 2589 +// 文件传输速度调节对话框 +#define IDD_FILE_SPEED 403 +#define ID_TOOL_FILE_SPEED 33085 +#define IDC_FSPEED_SLIDER 2590 +#define IDC_FSPEED_LABEL 2591 +#define IDC_FSPEED_RESET 2592 + // Next default values for new objects -// +// #ifdef APSTUDIO_INVOKED #ifndef APSTUDIO_READONLY_SYMBOLS -#define _APS_NEXT_RESOURCE_VALUE 403 -#define _APS_NEXT_COMMAND_VALUE 33085 -#define _APS_NEXT_CONTROL_VALUE 2590 +#define _APS_NEXT_RESOURCE_VALUE 404 +#define _APS_NEXT_COMMAND_VALUE 33086 +#define _APS_NEXT_CONTROL_VALUE 2593 #define _APS_NEXT_SYMED_VALUE 105 #endif #endif