Files
xmz7891 2061f9525f 2.3.0:手表界面精简 + 播放器 + 鼠标重做
手表端
- 功能页从 10 个杂项精简到 7 个(屏幕/鼠标/媒体/文件/电脑/语音/电源)
- 删掉:游戏封锁、待办、掷骰子、抽奖、壁纸、显示器开关、定时关机、
  剪贴板历史、性能/磁盘/电量、文件夹浏览、教室限制等
- 改成显式列按钮,不再把电脑端所有功能组无脑铺到表盘
- 远程鼠标控制重做:滑动区 + 左键/滚轮/右键三按钮
  滚轮点按=中键、上下滑=滚动
- 新增视频/音乐播放器(手表本地播放):进度拖动、左右滑快进退10秒、
  点画面播放暂停、上一/下一、播完自动下一首

电脑端
- 新增 kill_all(结束所有进程),白名单保护系统关键进程和自身
- 新增 media_list / media_pull(播放器数据源)
  安全边界:只允许媒体目录,用 relative_to 判断,防同前缀兄弟目录绕过

中转站
- known_devices 从 ID 集合改成「设备ID -> 配对码」映射
- 修复:管理员改码后关机超过 6 小时,改码会被超时清理冲掉
- 老格式 state 文件平滑升级
2026-10-18 11:39:14 +08:00

589 lines
31 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
## 2.3.0
- **手表端界面大改** —— 用户原话「杂七杂八功能都删掉」。功能页从 10 个杂项分页
精简成 7 个明确的:
| 分页 | 内容 |
|---|---|
| 屏幕 | 屏幕镜像 / 返回桌面 / 亮度 + / 亮度 - / 截屏 |
| 鼠标 | 远程鼠标控制 |
| 媒体 | 播放暂停 / 上一曲 / 下一曲 / 音量 +- / 静音 / **播放器** |
| 文件 | 发送文件 / 打开回收站 |
| 电脑 | 打开网址 / 快捷命令 / 进程管理 / 窗口置顶 / 结束所有进程 |
| 语音 | 语音播报 / 朗读剪贴板 |
| 电源 | 锁屏 / 睡眠 / 关机 / 重启 |
**删掉的**:游戏封锁、待办、掷骰子、抽奖、抛硬币、壁纸、显示器开关、
定时关机、剪贴板历史、性能/磁盘/电量、文件夹浏览、教室限制……
> 改了实现方式:以前每个分页靠 `TabDef.groups` 把电脑端上报的功能组
> 无脑铺上来 —— 电脑端加个功能,手表上就多一堆按钮。**那正是"乱"的来源。**
> 现在改成**显式列按钮**:手表上有什么,完全由代码决定。
- **远程鼠标控制重做** —— 用户要求「中间是一个鼠标,可以上下左右滑动控制,
下面有三个按钮,左边是左键,中间是那个滑轮,右边是那个右键」。
```
┌──────────────────────────┐
│ 滑动区(占满) │ 手指滑动 = 移动光标
├────────┬────────┬────────┤
│ 左键 │ 滚轮 │ 右键 │
└────────┴────────┴────────┘
```
滚轮按钮:**点一下 = 中键单击**,**上下滑 = 滚动**。
三个按钮就把左/中/右 + 滚轮全覆盖了。
- **新增视频 / 音乐播放器** —— 用户要求「有暂停开始,进度左右划,
下一个上一个」。
**设计取舍:让手表自己放,而不是让电脑放。**
如果让电脑放(调 `play_video`),电脑会打开它自己的播放器 ——
我们就**拿不到进度、也没法精确 seek**,那"进度左右划"就是假的。
手表自己放的话 `MediaPlayer` / `VideoView` 的
`getCurrentPosition` / `seekTo` 都是现成的,进度条和拖动全部真实可控。
代价:播放前要先把文件从电脑下到手表(走现有的分块传输)。
操作:
* 进度条拖动 = seek
* **画面区左右滑 = 快进/快退 10 秒**
* **点画面 = 播放/暂停**
* 上一 / 下一(播完自动下一首)
* 列表 = 从电脑的音乐/视频/下载/桌面目录里挑
- **电脑端新增 `kill_all`(一键结束所有进程)** ——
**白名单式保护**:本程序自己的 PID、父进程链、一批系统关键进程
(csrss / winlogon / lsass / svchost / explorer / dwm …)全部跳过,
否则一按就蓝屏或桌面消失。其余全杀,返回杀了几个、跳过几个、失败几个。
- **电脑端新增 `media_list` / `media_pull`** —— 播放器的数据源。
**安全边界**:只允许「音乐/视频/下载/桌面/接收目录」里的文件,
用 `Path.relative_to` 判断(不是字符串前缀 —— 那样「音乐-evil」
这种同前缀兄弟目录会被误判成子目录)。
- **中转站:管理员改过的配对码不再因关机 >6 小时丢失** 🔧
之前这条链会断:
1. 管理员在后台把码 `111111` 改成 `222222`
2. 那台电脑关机(或断网)超过 `DEVICE_TTL`(6 小时)
3. `snapshot()` 把设备删了,孤儿的码 `222222` 也被当垃圾清掉
4. 电脑开机,报自己本地的旧码 `111111`
5. 中转已经不记得改过码 → 收下 `111111`
6. **管理员的改码白做了**,手表手里是 `222222`,连不上
修法:`known_devices` 从「纯 ID 集合」改成「**设备 ID → 配对码**」映射。
改码时会同步写进历史,超时清理不动它。设备重新登记时以历史里的码为准,
并随 `register()` 的返回值告诉电脑端,**电脑端写回本地设置**。
兼容性:老格式的 `relay_state.json`(`knownDevices` 是纯列表)
能平滑升级 —— 加载时识别成「认识这台设备,但不知道它该用哪个码」,
下次它上报什么就用什么(跟改动之前一致)。
「删除设备」仍然忘干净(连历史一起删);「抹码」会清空历史里记的码
但保留设备 ID —— 否则抹码会白做。
## 2.2.0
- **手表端:输入配对码连上之后,先到一个选择页** ——
上面有两个按钮:
1. **远控** —— 进控制页(和以前一样)
2. **静默更新被控端** —— 让那台电脑自己升级到最新版
页面顶上会显示**已连接的电脑名**和**电脑端当前版本**
(比如「电脑端 2.1.5 → 可更新到 2.2.0」),一眼就知道要不要更新。
**为什么不直接进控制页**:老版本的被控端可能缺功能或者有 bug,
「先更新再远控」是更合理的顺序 —— 但也不强制,所以给用户自己选。
(自动切到中转服务器恢复时**不会**弹这个页面,还是直接回控制页 ——
用户本来就在用,中途弹一层会打断他。)
## 2.1.8
- **快捷栏的按钮做大** —— 上一版 30dp 在手表上按不准,手指按上去
一半在栏外。现在 46dp(接近 Android 建议的可点区域),字号 11→14。
- **快捷栏 4 个格子全部可以自定义** —— 上一版最后一个「显示桌面」
是写死不能改的,现在四格平等,想换哪个换哪个。
「显示桌面」变成一个普通的可选动作,默认仍放在第 4 格 ——
所以习惯不用改,但想换成别的也行。可选动作现在共 8 个:
传文件 / 屏幕镜像 / 鼠标控制 / 音效 / 关机 / 语音播报 /
投图到电脑 / 显示桌面。
- **修 Win7 上语音播报不能用** —— 以前只走 PowerShell 一条路,
而 Win7 上的 PowerShell 是 2.0 版,中文经命令行传进去容易乱码;
再加上 `powershell` 可能不在 PATH 里,就彻底播不出来了。
现在改成**多方案降级**,按"依赖越少越优先"排:
| 顺序 | 方案 | 依赖 |
|---|---|---|
| 1 | cscript + VBScript + SAPI5 | Windows 98 起就有,不用装任何东西 |
| 2 | wscript + VBScript + SAPI5 | 上一条被安全软件拦时的备选 |
| 3 | powershell + SAPI5 (COM) | 只依赖 PowerShell,**不需要 .NET** |
| 4 | powershell + System.Speech | 原来的做法,改用绝对路径 |
| 5 | powershell (按 PATH) + System.Speech | 最原始的,兜底 |
一条通了就记住它,以后直接用(不用每次从头试)。
**全都失败会明确报错** —— 以前是不等进程结束就返回"已播报",
明明没出声也报成功,那是在骗人。
## 2.1.7
- **手表端顶部快捷栏** —— 任何页面顶部都有一条栏,最多 4 个按钮:
- **最后一个是固定的「显示桌面」**(等于电脑上按 Win+D),**改不了**
- **前三个自己选**,在设置页里点一下从这 7 个里挑:
传文件 / 屏幕镜像 / 鼠标控制 / 音效 / 关机 / 语音播报 / 投图到电脑
- 也可以把某一格留空
- 还没连上电脑时它们是灰的(不是藏起来 —— "一直在但暂时不能用"
比"时有时无"更好理解)
- **远程鼠标控制(手表上的触摸板)** —— 拖动移动光标、单击左键、
双击右键,下面还有专门的左键/右键/滚轮按钮。
- **弹文字窗口的位置和大小可以自己设** —— 右下(默认)/ 右上 / 左上 /
左下 / 屏幕正中间 / 自定义坐标,字号 8~32 可调。
在电脑端设置窗口的「显示」里改。
- **屏幕被观看时的提示条改成默认不显示** ——
以前是强制弹的("有人在看你的屏幕,电脑前面的人该知道")。
现在默认关掉,跟常见远程工具一样全程无窗口;需要的话在
设置里可以打开。**这个开关是刻意保留的**:这软件应该始终有一个
"让本机用户看得见正在被控制"的选项可查。
- **中转后台能看到每台电脑的版本了**,并且可以直接点「更新」
让那台电脑自己静默升级(离线设备按钮置灰)。
- **手表端设置里可以开关「允许新设备连接」** ——
关掉之后只有配对过的电脑能连上来,教室里防别人乱连。
## 2.1.6
- **电脑端静默自动更新** —— 手表上点一下,电脑自己升到最新版,
全程不弹任何窗口,**中转地址、配对码、所有设置一个都不变**。
流程:手表点按钮 → 电脑端问中转"最新是哪版" → 下载并校验 →
起一个后台帮手 → 自己退出 → 帮手等它退出后静默装好 → 重新拉起。
几个关键点:
- **配置为什么不会丢**:配置存在 `%ProgramData%\ykxmz\data\`,
不在程序目录里。安装器升级只替换程序文件,不碰这个目录。
- **更新源是用户自己的中转站**,不是作者的服务器,也不是任何
写死的地址。中转没这功能(老版本服务端)时会明确提示
"先手动升级一次服务端"。
- **校验和不匹配就放弃这一轮**,保持现状(现状至少能用)。
自更新最怕的就是装上一个坏程序、然后它还自己继续更新。
手表首页新增「电脑端版本」按钮,点开就能看到
"电脑端 2.1.4 → 2.1.5",确认后才动手。
- **远程鼠标控制**:移动、左键、右键、中键、滚轮(含横向)。
这是"能直接操控电脑"的功能,所以参数校验写得很严:
非法动作、非法按键、非数字坐标全都会被拒。
- **一键显示桌面**(等于 Win+D)。
- **Windows 7 兼容性校验关卡**:打包时和回归里都会检查
(内嵌的是不是 3.8 运行库、**有没有**那个 Win7 上不存在的 DLL、
exe 是不是 32 位),不过就拒绝出包。
- 技术说明:
- 鼠标坐标用 SendInput 的 **0..65535 归一化**,而且**必须除以
(屏幕宽-1)**。少了那个 -1,最右边和最下边几像素点不到。
- `INPUT` 结构在 32/64 位下大小不同(28 / 40),代码按进程位数算。
- 目标窗口若是管理员权限的(UAC 提升过的),普通权限的注入会被
系统拦掉 —— 这是 Windows 的设计,不是 bug。被控端以管理员运行
就没问题。
## 2.1.5
- **修「Windows 7 装完报 dll 缺失」** —— 学校电脑装不上。
这一条是用户报的:学校的电脑是 Windows 7,装完提示缺 DLL。
**根因不是漏打包,是 Python 版本越界**:
| Python | 支持的系统 |
|---|---|
| **3.8** | Windows 7 及以上 ← 最后一个支持 Win7 的版本 |
| 3.9 ~ 3.13 | 只支持 Windows 8 及以上 |
Python 3.9 起用到了 `api-ms-win-core-path-l1-1-0.dll` 里的
`PathCchCanonicalizeEx`,而这个 DLL **Windows 7 上根本不存在**,
也没法用 api-set 转发(那套机制只在 Win8+ 生效)。
所以之前用 3.11 打出来的包,在 Win7 上必然报缺 DLL ——
**那个 DLL 不是"忘了放进包",是"放进去也没用"。**
**改法:改用 Python 3.8 打包**,而且选 **32 位** ——
32 位在 Win7 的 32 位和 64 位系统上**都能跑**,学校不用分两种发。
顺带加了两道自动关卡,以后不会再退化:
- 打包脚本 `windows\build_exe.ps1` **先校验 Python 版本**,
不是 3.8 直接报错退出(而不是默默打一个别人装不上的包)
- `_build\check_win7_compat.py` 校验产物:
内嵌是不是 3.8 的运行库、**有没有**那个要命的 DLL、exe 是不是 32 位。
打包时和回归套件里都会跑,不过就拒绝出包
安装包体积也从 14.4 MB 降到 **9.0 MB**(32 位运行库小一圈)。
- **顺手修了安装包测试里一个藏了很久的坑**:
`_build/test_installer_cycle.py` 里写死了 `ykxmz-setup-1.8.2.exe`,
于是它一直在**装一个不存在的旧包** → 静默失败 → 报出一堆
莫名其妙的失败("配对码实际是 xxx"、"版本显示 v1.8.2")。
改成自动找 `dist` 下版本号最新的包,以后不会再过期。
## 2.1.4
- **修一个"填了地址也连不上"的 bug**(手表端)。
中转地址栏里填 `yk.xxmxxs.top` 这种**没写 `http://` 开头**的地址时,
点首页那个「检查服务器」会报:
```
MalformedURLException: no protocol: yk.xxmxxs.top/v1/health
```
原因是:补协议头的逻辑只写在连接那一条路上,
「检查服务器」直接拿原始字符串拼 URL —— **同一个地址,
连接能用,检查却崩**。
现在把补协议头收到**唯一一个入口**(读地址的地方),
所有用到地址的地方都从那里取,以后再加新入口也不会漏。
规则和电脑端保持一致:
- `IP` / `localhost` / `*.local` → 用 `http://`
- 域名 → 用 `https://`
- **修正 README 里几处不准确的说法**,以及过时的版本号:
- 被控端只装在**一台**电脑上(讲台那台或你自己那台),
原文写成"看学生机"是错的 —— 它看不到别的机器
- 课堂那几项功能如实说明:改的是**本机** hosts、结束的是**本机**进程,
都是可逆的,下课后点「一键恢复全部」就还原
- 成品文件名从 1.8.2 更新到当前版本,并且以后发版会自动跟着改
## 2.1.3
- **支持「自己搭的、没有证书的中转」**(新服务器就是这种)。
中转不再是必须挂在 Cloudflare 隧道后面了。现在可以直接跑在
一台有公网 IP 的机器上,客户端填 `IP:端口` 就能连 —— 延迟、稳定性
都比隧道好得多。为此改了两处客户端:
- **手表端**:填 `yk.xxmxxs.top:13245` 这种**没写协议头**的地址时,
现在会按「IP / localhost / 本地域名 → 明文,域名 → 加密」来猜,
**和电脑端规则一致**。原来一律补成 `https://`,而那台机器没有证书,
结果是**永远连不上**,报的还是 SSL 错误,很容易让人白查半天证书。
- **手表端**:允许明文流量。Android 9 以上默认禁止,不加这一条的话
请求会被系统直接掐掉,日志里只有一句含糊的
「Cleartext HTTP traffic to ... not permitted」。
> 说明:中转上跑的内容(配对令牌、画面、文件)本来就是加密过的,
> 明文只暴露地址和设备名。想要全程加密的话,把域名解析到这台
> 服务器再签一张免费证书即可。
- 顺手清掉了电脑端一段函数内的重复代码(`return` 之后还有一份一样的
拷贝,缩进仍在函数体内所以不报错,但读起来很迷惑)。
## 2.1.2
- **隧道稳定性加固**(继续修「网站还是容易挂」)。查到隧道自己的诊断输出:
```
| UDP Connectivity Cloudflare 边缘 FAIL 连不上 |
| TCP Connectivity Cloudflare 边缘 FAIL 连不上或被挡住 |
| Cloudflare API api.cloudflare.com:443 PASS 通的 |
| ERROR: Allow outbound QUIC traffic on port 7844 or use HTTP2. |
```
也就是说:**443 通,7844 不通**,而且是**一阵一阵的**
(过几分钟自己又好了,然后再次断)。Cloudflare 隧道的边缘连接走 7844,
这条线路对它是间歇性阻断 —— 这属于运营商那一侧,设备改不了。
**但可以让它自己去适应**:
- 两条隧道实例原来**各自写死一个协议**(一条只走 QUIC、一条只走 HTTP/2)。
那一刻如果 7844 的 UDP 和 TCP 都不通,两条一起死,没有退路。
现在都改成 **自动选择**,cloudflared 自己在 QUIC / HTTP/2 之间挑
当前能通的那条。等于所有连接都有自适应能力,而不是
"8 条赌 UDP、2 条赌 TCP"。
- 重试次数从 5 提到「一直重试」。原来失败 5 次就退出、靠系统重新拉起,
每次退出到重启之间网站都是断的;而这条线路的抖动是分钟级的,
5 次根本扛不过去(实测隧道每 3~10 分钟就被重启一次,公网跟着 530)。
现在抖动期间连接自己恢复,整条隧道不退出。
**改完实测**:连接数 7+2(接近满配 10),公网连测 5 次全部 200。
- 顺手加了日志轮转(隧道日志已经涨到 3 MB,这台小机器硬盘不大)。
## 2.1.1
- **修一个会让网站整个挂掉的死锁**(这是「网站还是容易挂」的真因)。
在装了中转服务器的那台机器上,网络调优服务和隧道之间会互相等:
```
网络调优服务(nettune): "我必须先于隧道启动完"
网络调优脚本第 4 步: "重启隧道,让新参数生效" ← 卡在这里
```
它在**自己还没结束**的时候去重启一个「必须等自己结束才能启动」的服务,
系统判定成顺序冲突,那一步就永远不返回。结果网络调优一直卡在
「正在启动」,隧道被挡着起不来,**公网就是 530**。
实测卡了 9 分半。而且**日志里一句报错都没有**,
手动跑那个脚本却完全正常(那时没有顺序约束)——
所以特别难查,是靠这次新加的监测单元抓到的
(它记录到「连续 3 次不通」并把现场留了下来)。
**改法**:让脚本知道「这次是服务在调我」,那就跳过重启隧道那一步。
开机时本来也不需要它 —— 顺序就是调优先、隧道后,那时隧道还没起来。
> 这个坑以前一直藏着:设备上那份旧的服务定义里有一个写法错误,
> 导致它在更早的步骤就报错退出了,反而没走到会死锁的那一步。
> 把服务定义改对之后,死锁才露出来。
- 另外这一版的服务端包也带上了上面那个修复。
**2.1.0 的服务端包是有问题的**,请用 2.1.1 重新部署。
## 2.1.0
- **网站挂了会自己救**:中转服务器上常驻一个监测单元,每 60 秒从**公网**
查一次(不是查本机 —— 本机通不代表用户能打开)。连续 3 次不通就按阶梯
自动抢救:
| 级 | 动作 | 代价 |
|---|---|---|
| 1 | 重启隧道 | 不动中转,在线设备不掉线 |
| 2 | 重启中转服务 | 设备要重连,但很快 |
| 3 | 重新施加网络调优 | MSS / MTU 跑偏时用 |
| 4 | 重启无线网卡 | 4G / WiFi 卡死时用 |
| 5 | 重启整机 | 最后的底牌,**默认不开** |
每做完一级立刻复验,好了就停。救完 10 分钟内不再动手(防抖 ——
否则预案刚重启完隧道还没连上,下一次检查又救一遍,
来回重启反而永远连不上)。
- **网站出问题会自动留下诊断报告**:万一五级都没救回来,服务端会把现场
(内存、进程、隧道连接数、路由和 MTU、三份日志尾部、内核异常)
整理成一份 txt 留在服务端,需要排查时直接取来看就行。
只保留最近 30 份,不会把设备塞满。
每次自动抢救成功,也会把「第几级奏效」记进知识库,
下次同类问题优先试历史上管用的那一级。
- **网络热门音效**:手表上新增「音效」按钮,点一下电脑就响。
内置 8 个(冰冰冰 / 啊哈哈哈 / 老牧师 / 叮 / 当当当 / 警报 / 鼓点 / 弹簧)。
> 说明一下**版权**:网上那些「冰冰冰」「啊哈哈哈」是有版权的真实录音,
> 不能打包进安装包。所以内置的是**程序合成**的版本(正弦/方波现场算),
> 名字对着感觉来,但不是那些录音本身。
> 想要一模一样的一手素材,把 mp3/wav 丢进电脑的 `data\sfx\` 目录,
> 点「刷新」就出现在列表里,照样能远程播。目录里放了一份说明。
- **修「安卓设置页一片空白」**:设置页建好了但**忘了挂到窗口上**
(少了 `root.addView`),`showOnly()` 让它可见也没用 —— 它根本不在
视图树里。已修,并加了断言盯着「每个面板都必须挂到 root、
并且纳入 showOnly()」—— 这类漏挂编译不报错、只在运行时表现为空白。
- **全量测试改成后台静默**:会开窗口的 6 个阶段(含开**全屏**那个)
现在跑在独立的 Windows 隐藏桌面上 —— 窗口是**真的**(全屏、可见、
几何、Win32 枚举都真实),但屏幕上什么都看不到,也不会锁你的屏。
顺带修了一个一直误判的检测:判断「锁屏」时只看 `OpenInputDesktop`
成不成功是不对的 —— **锁屏时它同样成功**(那时输入桌面是 Winlogon)。
所以截屏类测试在锁屏时被记成 FAIL 而不是 SKIP,把真问题淹掉了。
改成看输入桌面的**名字**。现在锁屏也能跑全量:该 SKIP 的 SKIP,
该跑的照跑。
## 2.0.0
- **安装时就能设中转服务器**:安装向导那一页现在是两个输入框 ——
**配对码**和**中转服务器**。装的时候是"第一次设置",那时候最该一次
把地址填好,不然装完还得去双击 exe 找设置窗口,很容易漏。
只填域名就行(自动补 `https://`),留空 = 只走局域网。
批量部署同样支持:`/VERYSILENT /CODE=246810 /RELAY=relay.你的域名`
- **手表端新增「设置」页**:以前设置散在首页(只有一个"中转设置"按钮),
现在统一收进来,在里面调:
- **中转服务器**(填写 / 一键清空)
- **记住的配对码**(显示 / 清除)
- **已配对的电脑**(看数量 / 清空)
- **关于**(版本号 + 连接顺序说明)
- **中转地址改成手动填,默认留空**:以前有一版把作者的服务器地址写死成
默认值,第一次运行就存进了偏好设置,装新版本也不会清 ——
看起来就像"默认还是别人的中转站"。现在默认是空的,
并且会做**一次性迁移**把那个旧的内置地址清掉
(只清完全相等的,你自己填的不会动)。
- **修「局域网连上后要推出去点设备才能控制」**:手表上有四个页面,
切换时靠手工藏上一页,新加的「局域网连接」页漏藏了 ——
所以从它连上之后控制面板其实已经显示,却被盖住看不见。
- **修「双击 exe 没反应」**:装完之后双击现在会打开设置窗口。
- 新增**版本号一致性检查**和**中转地址默认值检查**两道断言,
防止这类"漏改一处"的问题再出现。
## 1.9.0
- **被控端终于有设置窗口了**:装完之后双击 `ykxmz.exe` 就能打开,里面可以改
**配对码**、**中转服务器**、**允许新设备接入**、开机自启。
以前双击是"什么都不弹",只能靠命令行参数改配置。
> 顺带修了一个很隐蔽的打包问题:PyInstaller 的 `--hidden-import` 里漏了
> `lanremote.ui`(设置窗口那套 tkinter 代码)。源码跑得好好的,
> 但**打包出来的 exe 一跑就崩**,用户看到的还是"双击没反应"。
- **修「局域网连上后没反应」**:手表上有四个页面,切换时靠手工藏上一页,
而新加的「局域网连接」页**漏藏了** —— 所以从它连上之后,控制面板其实
在底下显示了,却被盖住看不见。必须"推出去点一下设备"才看到。
根子是"每处切换都手写一串 setVisibility",改成统一入口 `showOnly()`,
以后加页面不会再漏。
- **修「按一下没反应」的真因**:中转那条长轮询(最长 60 秒)和用户操作
共用了同一个 HTTP 连接,长轮询占着连接时操作请求发不出去,
线程直接死掉,之后所有操作都没反应。改成各用各的连接。
- **中转地址默认留空**:需要跨网络时自己填。只在一个 WiFi 里用就什么都不用配,
那样手表和电脑直接连,最快也不耗流量。
- 新增**版本号一致性检查**:版本号散落在 8 个地方(exe 文件属性、安装包、
APK、许可页…),靠脚本+人工替换很容易漏。实测就漏了两处:
`version_info.txt` 和许可页都还写着 1.7.1 —— 用户在"文件属性"里
看到一个错三个版本的号。现在有断言钉住。
## 1.8.2
- **下载快了几十倍**:安装包和 APK 改成由 Cloudflare 的边缘节点直接发送。
原来每次下载都要穿过隧道回到那台 4G 小机器上取文件,实测吞吐只有
3~67 KB/s,15 MB 的安装包根本下不动(还会中途断掉)。
现在改走边缘缓存:同一个文件实测从 **17 KB/s 提到 695 KB/s**,
APK 从 3 KB/s 提到 101 KB/s,并且不再消耗 4G 流量。
- **跨网络连接更稳**:隧道改成**两种协议同时跑**,一共 10 条连接。
两种协议各有各的毛病 —— 实测这条线路上运营商对 UDP 有限制,
纯 QUIC 的拨号成功率只有 72%;而纯 HTTP/2 一旦丢包就容易卡住
(一条 TCP 上丢一个包,所有请求一起等)。
两个一起跑就是互相兜底:QUIC 拨号失败的那部分由 HTTP/2 顶着,
HTTP/2 卡住的时候 QUIC 的恢复更快。
实测 25 分钟连续可用率 **50/50 = 100%**(改之前是 96~98%),
尾部延迟 P99 从 3295ms 降到 2632ms。
- 修**网卡 MTU 和 QUIC 不匹配**:之前只给 TCP 做了 MSS 钳制,
而 QUIC 走 UDP 完全不受保护,包一大就被中间设备悄悄丢掉。
把网卡 MTU 降到 1400 之后,QUIC 建齐 10 条连接的时间从
**28 秒缩到 12 秒**。
- 修**响应头不一致**:下载接口之前对 GET 和 HEAD 报的缓存信息不一样,
部分下载工具(IDM、迅雷)探测时会把文件误判成不可缓存甚至空文件。
- 修**偶尔闪一下"已断开"**:原来只要有一次请求失败就立刻显示离线,
而 4G 链路上本来就有 2~4% 的偶发失败、一两秒就自己恢复。
现在改成**连续失败 3 次**才判离线 —— 真的断了仍然如实显示。
## 1.8.1
- 修**局域网连接被中转劫持**(重要):
只要「中转设置」里填了地址,点「局域网连接」填好 IP、端口、
配对码之后,程序**仍然走中转**,完全无视你填的局域网地址。
中转慢的时候要等 40 秒才报错,看起来就像"点了一点反应都没有"。
现在改成:局域网优先直连(6 秒超时),连不上才退回中转
- 修**已配对电脑的地址过期不提示**:
电脑换了网络之后(比如从 192.168.2.x 换到 192.168.10.x),
列表里还是旧地址,点一下必然失败。现在会标出「⚠ 地址可能已过期」,
并且跳过注定失败的直连,直接通过中转查询最新地址
- **长轮询从 15 秒延长到 60 秒**,跨网络更稳:
隧道每次请求要多花 1~2 秒(边缘路由 + 回源),而这个开销是按
**次数**收的 —— 每次都要吃一遍。拉长到 60 秒把请求数降到 1/4,
撞上丢包/重连窗口的概率也降到 1/4。
**命令响应速度不变**:有数据时立刻返回,不是等满 60 秒。
- 修局域网直连成功后打出误导性日志的问题
## 1.8.0
**这一版主要是「修看不见的稳定性问题」。**
- 修**跨网络老断**(Error 1033 / 502 / 530 的真因):
4G 链路会**静默断开 TCP 连接**(不发 FIN/RST,双方都以为还活着),
Cloudflare 把请求发到这种"僵尸连接"上就报错。
而 Linux 默认要 **2 小时**才发现连接死了 —— 中间这段时间
服务一直"看着在线、实际打不开"。
现在改成 30 秒探测、60 秒内发现并重连
- 修**跨网络抖动**:隧道连接数从 2 提到 4。
只剩 1 条连接时跨机房回源会失败,实测可用率 0/12;
提到 4 条后稳定 12/12
- 修**掉电重启后恢复太慢**:原来开机要 **2 分 10 秒**公网才恢复,
那段时间浏览器看到的就是 Error 1033。
根因是系统里 NetworkManager 和 systemd-networkd 同时在跑,
后者等一个不归它管的网络,干等 2 分钟超时失败,
把启动流程一起拖住了。改完 **17 秒**就绪,掉电重启后 24 秒公网可用
- 修**看门狗自己制造不稳定**:它每隔 50 秒重启一次隧道,
但隧道重建 4 条连接要 30~60 秒 —— 每次还没建齐就被下一次打断,
永远停在"只剩 1 条"的状态。现在重启后有宽限期,
并且会区分"没建好过"和"建好过又垮",后者立刻重启
- **官网重新设计**:层次更清楚,白色简洁风格
- **官网新增产品展示**:手表界面预览(颜色和布局与真实手表一致)、
电脑端真实截图、两种连接方式对比图
- 清理**僵尸设备记录**:设备列表原来只增不减,
实测一天攒了 75 条无效记录,拖慢手表和网页访问。
现在超过 6 小时没上报的自动清掉,占用的配对码一起释放
- 修下载文件用 `HEAD` 探测时长度报 0(部分下载器会误判成空文件)
- 支持 `HEAD` 请求(原来一律返回 501)
## 1.7.1
- 修**卸载卡死**:从控制面板卸载时进度条永远走不完。
根因是被控端在无控制台的隐藏进程里调 `AllocConsole` 和
读控制台输入,会永久阻塞
- 修**安装回滚**:旧版本程序还在后台跑时,安装器关不掉它,
弹「无法关闭所有应用程序」,静默安装会整个回滚 ——
用户看到的是"装了没反应"
- 修卸载残留:开机自启注册表项没删掉、安装目录留个空壳
- 修手表连上后**一片白屏**:分页初始化函数从没被调用过,
标签栏里只剩一个孤立的指示器
- 修「被控端已关闭新设备配对」把重装手表的人永久挡在外面:
配对码本身就是钥匙,拿着正确的码就该放行
- 手表端应用名改成 ykxmz
- 修跨网络**延迟高**:隧道退回了 QUIC(`--protocol http2` 参数丢失),
可用率只有 48%;恢复 HTTP/2 后可用率 100%
- 网络调优持久化:TCP 缓冲 4 MB、FastOpen、
空闲后不重置拥塞窗口(长轮询场景关键)
- 手表提示改成自诊断式:连不上时直接打出双方地址,
一眼看出是网段不同还是连错了 WiFi
- **官网重新设计**:导航 / 功能 / 三步上手 / 下载 / 常见问题
- 官网改成白色简洁风格
## 1.7.0
- 电脑端改成 **Windows 安装包**(Inno Setup),双击安装,不再需要解压 zip
- 安装向导里填 6 位配对码,装完手表直接连,不用再跑一次设置
- 安装包支持静默批量部署:`ykxmz-setup-1.7.0.exe /VERYSILENT /CODE=123456`
- 三份说明文档合并进安装向导,必须接受才能继续
- 修配置分裂问题:管理员装的配对码,普通用户账号看不到(数据目录改成按安装位置判断)
- 修装到 Program Files 后报「拒绝访问」:ProgramData 数据目录自动授权
- 修安装卡死:`--code` 命令处理完不返回