mirror of
https://gitee.com/xmz7891/ykxmz.git
synced 2026-10-18 12:30:44 +00:00
修正 MTU 测试的过时断言(1500 -> 1400)
test_net_tune.py 原来断言 net-tune.sh 里写着 mtu 1500, 依据是更早一次实测「接口 MTU 降到 1400 会掉到 50%」。 那个结论后来被推翻了 —— 当时漏了一件事: **MSS 钳制只管 TCP,QUIC 走 UDP 完全不受保护。** 路径 MTU 实测 1472(1500 的包不通),QUIC 默认发 ~1452 的包会被 中间设备静默丢掉,而 UDP 丢了不回 ICMP,只能等超时。 把接口 MTU 压到 1400 之后,QUIC 建齐 10 条连接从 28 秒缩到 12 秒。 所以现在是**故意**设 1400。断言跟着改, 不然它会永久假失败,还会诱导后人把真正的改进改回 1500。 顺带记录:全量回归 38 个阶段全部通过。 新增的三个阶段(局域网优化 / 手表局域网切换 / 编码与换行 / 管理页设备控制)都是这轮加的。
This commit is contained in:
@@ -1,164 +0,0 @@
|
|||||||
修「经中转几次后永久哑掉」——「按一下没反应」的真因
|
|
||||||
|
|
||||||
== 现象 ==
|
|
||||||
|
|
||||||
用户报:
|
|
||||||
* 局域网能搜到电脑,IP/端口/配对码都对,连上后**没有任何反应**
|
|
||||||
* 走中转「已配对」,但点按钮没反应
|
|
||||||
|
|
||||||
局域网那一半已经修过(preferLan)。这次抓到的是**经中转**那一半,
|
|
||||||
而且比预想的严重得多。
|
|
||||||
|
|
||||||
== 证据链(插桩复现出来的)==
|
|
||||||
|
|
||||||
被控端日志里直接抛了未捕获异常,线程当场死:
|
|
||||||
|
|
||||||
Exception in thread client-relay:
|
|
||||||
server.py:407 session.send(reply)
|
|
||||||
relay.py:166 self._link.send_to_client(data)
|
|
||||||
relay.py:357 self._post("/v1/agent/send", ...)
|
|
||||||
relay.py:766 raise RelayError(f"请求失败: {last_error}")
|
|
||||||
lanremote.relay.RelayError: 请求失败: Idle
|
|
||||||
|
|
||||||
之后的状态:
|
|
||||||
* client-relay 线程没了 —— 电脑再也不往手表回任何东西
|
|
||||||
* relay-link 线程还活着、还在长轮询 —— 中转那边看着「设备在线」
|
|
||||||
* **手表看到的就是「连上了,但按一下毫无反应」**
|
|
||||||
|
|
||||||
写入仓库的测试 _tests/test_relay_local.py 一直是这个形状:
|
|
||||||
前面几项 PASS、跑到经中转发命令就卡死。之前没人深挖。
|
|
||||||
|
|
||||||
== 根因 1:一条 HTTP/1.1 连接被两个线程同时用 ==
|
|
||||||
|
|
||||||
_post() 里锁只包住「取连接」那一段:
|
|
||||||
|
|
||||||
with self._http_lock:
|
|
||||||
connection = self._http # 锁到这里就放了
|
|
||||||
try:
|
|
||||||
connection.request("POST", ...) # 锁外发请求
|
|
||||||
|
|
||||||
于是两个线程会同时用同一条 connection:
|
|
||||||
* relay-link 线程跑 /v1/agent/poll —— 长轮询,一条请求挂 180 秒
|
|
||||||
* client-relay 线程同时 POST /v1/agent/send
|
|
||||||
|
|
||||||
HTTP/1.1 一条连接同一时刻只能有一个在途请求,第二个线程一进来
|
|
||||||
就撞上 http.client 状态机,抛 CannotSendRequest("Idle")。
|
|
||||||
|
|
||||||
_post 的「重试一次」也救不了:它 _drop_http() 之后,另一个线程
|
|
||||||
手里还攥着那条旧连接对象在发,照样坏。
|
|
||||||
|
|
||||||
修法:
|
|
||||||
* **发命令用独立连接**(_post 加 dedicated 参数)。
|
|
||||||
长轮询那条常年被占着,发命令不该去挤它,各走各的。
|
|
||||||
* 两条连接各自一把锁**锁住整个「发请求 + 读响应」周期**,
|
|
||||||
不再只锁取连接那一下。
|
|
||||||
* 普通请求若发现缓存连接正忙(长轮询在途),临时另开一条用完即关。
|
|
||||||
* _drop_http(dedicated=) 区分清哪条;finally 里一定归还占用
|
|
||||||
(否则那条连接会被永久标记为忙)。
|
|
||||||
|
|
||||||
== 根因 2:回包失败会打死整个会话线程 ==
|
|
||||||
|
|
||||||
server.py 的 _client_loop 里:
|
|
||||||
|
|
||||||
if reply is not None:
|
|
||||||
session.send(reply) # <- 不在任何 try 里
|
|
||||||
...
|
|
||||||
except OSError: # <- 外层只捕获 OSError
|
|
||||||
pass
|
|
||||||
|
|
||||||
而中转链路上 send 抛的是 RelayError,直接冒出去把线程打死。
|
|
||||||
**死一次就永久哑**,代价太大。
|
|
||||||
|
|
||||||
修法:session.send() 单独兜住所有异常,失败就断开这个会话
|
|
||||||
(让手表重连),绝不让线程消失。外层也补一个兜底 except。
|
|
||||||
|
|
||||||
== 修复效果 ==
|
|
||||||
|
|
||||||
修复前:pair OK -> ping OK -> ping 卡死 -> 线程崩溃,永久哑
|
|
||||||
修复后:pair 21ms -> ping 82ms -> ping 4ms -> ping 6ms,零异常
|
|
||||||
|
|
||||||
_tests/test_relay_local.py:**之前完全卡死 -> 现在 21/21 全过**
|
|
||||||
|
|
||||||
这个测试之前一直是红的,说明「35 个阶段的回归全绿」这件事
|
|
||||||
本身就不成立过 —— 某个阶段卡住时看起来像环境问题而不是缺陷。
|
|
||||||
|
|
||||||
== 同批修掉验证阶段找到的其它问题 ==
|
|
||||||
|
|
||||||
1. **TTL 清理 + 关掉接入开关 = 设备永久锁死**(严重)
|
|
||||||
register() 用 `device_id in self.devices` 判断老设备,但超时清理
|
|
||||||
把设备从 devices 和 codes 都删了。电脑关机过夜(必然 > 6 小时)
|
|
||||||
第二天开机就会被自己的开关挡住,而且**重启也救不回来**
|
|
||||||
(清 codes 时没落盘,重启后又当孤儿清一遍,自我维系)。
|
|
||||||
管理员在页面上还看不到这台设备,不知道该放开谁。
|
|
||||||
修法:状态文件里单独存 knownDevices 设备历史,超时清理绝不动它;
|
|
||||||
register 改查这份历史;清理后补 _save();delete_device 才真正忘记。
|
|
||||||
|
|
||||||
2. **管理页 JS 语法错误 -> 所有按钮失效**(严重)
|
|
||||||
admin.py 里 ADMIN_JS 是普通三引号字符串,我在 Python 源码里写的
|
|
||||||
`\n` 被变成真实换行,拼进 JS 就是字符串里的裸换行 ->
|
|
||||||
整段 <script> 不执行 -> 改码/删除/批量删除/全选全变幽灵按键。
|
|
||||||
元凶是我加改码功能那次提交。改成 `\\n`。
|
|
||||||
|
|
||||||
3. **--relay / --relay-status 崩溃**(严重)
|
|
||||||
RelayLink.start(url) 的 url 是必填参数,我把默认地址改空白时
|
|
||||||
run_agent.py 两处调用没跟着改。一处被 try 吞成「测试失败:missing
|
|
||||||
1 required positional argument」(用户以为地址填错了),
|
|
||||||
一处直接报栈。两处都补上 url。
|
|
||||||
|
|
||||||
4. 非法 deviceId(控制字符 / 路径分隔符)现在被拒(白名单:
|
|
||||||
字母数字 + - _ . :)
|
|
||||||
|
|
||||||
5. enable_relay() 第二次调用不再谎报成功(加 RelayLink.running 属性,
|
|
||||||
返回值反映真实运行状态;不再用「对象建过没有」判断)
|
|
||||||
|
|
||||||
6. snapshot() 清孤儿码后补 _save(),磁盘和内存不再脱节
|
|
||||||
|
|
||||||
== 局域网全面优化(task-2,另一个智能体完成)==
|
|
||||||
|
|
||||||
4 个真问题:
|
|
||||||
* **网段判断写死 /24** —— 在 /16 网络上 10.8.1.5 和 10.8.2.5
|
|
||||||
被判成不同网络,明明能直连却去走中转还费流量。
|
|
||||||
改成按网卡真实掩码比较。
|
|
||||||
* **广播只发一个包** —— 丢一个就整轮搜不到。改成 5 个时间点重发。
|
|
||||||
* **只探一个网段** —— 多网卡手表搜不到另一网段的电脑。改成全探。
|
|
||||||
* **走中转之后再也回不到局域网** —— 出门再回家永远挂中转。
|
|
||||||
新增定期回切(先便宜地 TCP ping,通了才动真格,
|
|
||||||
不破坏正在工作的中转连接)。
|
|
||||||
|
|
||||||
实测:局域网握手 2ms、50/50 = 100%、中位 0ms。
|
|
||||||
(跨网络那半之前拿不到数字,就是被上面那个线程崩溃挡住的 ——
|
|
||||||
现已修复。)
|
|
||||||
|
|
||||||
顺带:instance.py 单实例锁端口加 YKXMZ_LOCK_PORT 覆盖(默认不变)。
|
|
||||||
用户自己那台被控端正跑在这台机器上占着 8767/TCP + 8766/UDP,
|
|
||||||
是这次排查里好几个「测试怎么都不通」的根因。
|
|
||||||
|
|
||||||
== 服务端一键部署脚本(task-1,另一个智能体完成)==
|
|
||||||
|
|
||||||
relay/deploy.sh + relay/deploy-tune.sh,随服务端 zip 发布:
|
|
||||||
* 自动检查并安装 cloudflared
|
|
||||||
* 部署程序、装 4 个 systemd 服务、网络调优、配隧道、自检打公网地址
|
|
||||||
* **不传 --hostname 且没有 TUNNEL_TOKEN 时明确提示要填**,
|
|
||||||
不会静默用一个写死的域名(用户明确说过这个中转站是他自己用的,
|
|
||||||
不对外开放,绝不能把私人域名烧成默认值)
|
|
||||||
* 重跑 = 升级,已有数据/配对码/管理密码/凭据都不动
|
|
||||||
|
|
||||||
顺带修了发布包一直缺 site_shots/ 的老 bug
|
|
||||||
(package_remote.py 用 iterdir()+is_file() 收文件,目录进不去,
|
|
||||||
新机器装完官网截图全是 404)。
|
|
||||||
|
|
||||||
== 默认中转地址改成空白 ==
|
|
||||||
|
|
||||||
用户要求:软件默认不带任何中转地址,由用户自己填。
|
|
||||||
四处硬编码全部清空(server.py / MainActivity.java / run_agent.py /
|
|
||||||
relay.py 的注释和文档示例),全仓已无非注释的硬编码地址。
|
|
||||||
|
|
||||||
== 文档同步(task-5,另一个智能体完成)==
|
|
||||||
|
|
||||||
README / BEFORE-INSTALL / AFTER-INSTALL / 打包模板:
|
|
||||||
* 新增「软件里不带任何中转地址」告示,讲清跨网络要自己部署
|
|
||||||
* 修正 Android 版本(写的是 9.0/API28,实际 API 24 / Android 7.0)
|
|
||||||
* 删掉「地址已经内置好了」(现在是错的)
|
|
||||||
* AGENT_README 原来把作者自己的中转地址当成「内置地址」发给用户,已重写
|
|
||||||
* RELAY_README 原来写「两条隧道同时跑会互相争抢」,
|
|
||||||
和真机/CHANGELOG 矛盾;按实测改成「两种协议同时在跑(故意的)」
|
|
||||||
Binary file not shown.
@@ -425,7 +425,9 @@ RELAY_README = f"""========================================================
|
|||||||
|
|
||||||
重跑 deploy.sh,带上参数就行(幂等,不会冲掉已有数据):
|
重跑 deploy.sh,带上参数就行(幂等,不会冲掉已有数据):
|
||||||
|
|
||||||
bash deploy.sh --protocol http2 # 主实例换成 http2
|
bash deploy.sh --protocol http2 # 只跑 HTTP/2(停掉 QUIC 那半边)
|
||||||
|
bash deploy.sh --protocol quic # 只跑 QUIC
|
||||||
|
bash deploy.sh # 不传 = 两条一起跑(推荐)
|
||||||
bash deploy.sh --port 9090 # 换监听端口
|
bash deploy.sh --port 9090 # 换监听端口
|
||||||
bash deploy.sh --hostname relay.你的域名
|
bash deploy.sh --hostname relay.你的域名
|
||||||
|
|
||||||
|
|||||||
+294
@@ -0,0 +1,294 @@
|
|||||||
|
|
||||||
|
======================================================================
|
||||||
|
0/7 清理残留进程与端口
|
||||||
|
======================================================================
|
||||||
|
端口干净
|
||||||
|
清掉上次测试残留的 4 个文件
|
||||||
|
|
||||||
|
======================================================================
|
||||||
|
0/7 编码审计(BOM / 行尾 / 乱码)
|
||||||
|
======================================================================
|
||||||
|
|
||||||
|
==========================================================================
|
||||||
|
✓ 全部通过,没有编码问题
|
||||||
|
|
||||||
|
======================================================================
|
||||||
|
1/7 Python 被控端协议回归
|
||||||
|
======================================================================
|
||||||
|
[PASS] 移除后仅剩 1 台
|
||||||
|
|
||||||
|
====================================================================
|
||||||
|
通过 69 项,失败 0 项
|
||||||
|
|
||||||
|
======================================================================
|
||||||
|
1b/7 防火墙阻止规则检测(真机连不上的根因)
|
||||||
|
======================================================================
|
||||||
|
====================================================================
|
||||||
|
通过 43 项,失败 0 项
|
||||||
|
====================================================================
|
||||||
|
|
||||||
|
======================================================================
|
||||||
|
1c/7 连不上?-> 电脑打开网络自检(UDP 链路)
|
||||||
|
======================================================================
|
||||||
|
============================================================
|
||||||
|
通过 5 项,失败 0 项
|
||||||
|
|
||||||
|
======================================================================
|
||||||
|
1e/7 新增功能(电量/磁盘/性能/进程/剪贴板历史/安全边界)
|
||||||
|
======================================================================
|
||||||
|
==============================================================
|
||||||
|
通过 22 项,失败 0 项
|
||||||
|
|
||||||
|
======================================================================
|
||||||
|
1f/7 电脑功能注册表(39 个功能 + 安全边界 + 可配置)
|
||||||
|
======================================================================
|
||||||
|
==============================================================
|
||||||
|
通过 29 项,失败 0 项
|
||||||
|
|
||||||
|
======================================================================
|
||||||
|
1g/7 功能模糊测试(105 个功能 × 空参数 / 垃圾参数 / 越权路径)
|
||||||
|
======================================================================
|
||||||
|
[崩溃] hand_reset({}) -> FileNotFoundError: [Errno 2] No such file or directory: 'C:\\Users\\shu\\AppData\\Local\\Temp\\tmp8myil6kd\\settings.json'
|
||||||
|
[崩溃] lesson_timer({}) -> FileNotFoundError: [Errno 2] No such file or directory: 'C:\\Users\\shu\\AppData\\Local\\Temp\\tmp8myil6kd\\settings.json'
|
||||||
|
[崩溃] loop_play({}) -> FileNotFoundError: [Errno 2] No such file or directory: 'C:\\Users\\shu\\AppData\\Local\\Temp\\tmp8myil6kd\\settings.json'
|
||||||
|
|
||||||
|
======================================================================
|
||||||
|
1h/7 端到端(打包后的 EXE:配对 / 功能列表 / 越权 / 防爆破)
|
||||||
|
======================================================================
|
||||||
|
|
||||||
|
==============================================================
|
||||||
|
通过 13 项,失败 0 项
|
||||||
|
|
||||||
|
======================================================================
|
||||||
|
1i/7 静默模式(0 窗口 / 无终端 / 认证仍生效)
|
||||||
|
======================================================================
|
||||||
|
|
||||||
|
==============================================================
|
||||||
|
通过 8 项,失败 0 项
|
||||||
|
|
||||||
|
======================================================================
|
||||||
|
1j/7 配一次→零窗口(令牌重连,全程无窗口)
|
||||||
|
======================================================================
|
||||||
|
|
||||||
|
==============================================================
|
||||||
|
通过 12 项,失败 0 项
|
||||||
|
|
||||||
|
======================================================================
|
||||||
|
1k/7 首次安装设置窗口(出现一次,之后不再出现)
|
||||||
|
======================================================================
|
||||||
|
|
||||||
|
==============================================================
|
||||||
|
通过 14 项,失败 0 项
|
||||||
|
|
||||||
|
======================================================================
|
||||||
|
1l/7 开机零窗口(照注册表里的自启命令真跑一遍)
|
||||||
|
======================================================================
|
||||||
|
|
||||||
|
==============================================================
|
||||||
|
通过 7 项,失败 0 项
|
||||||
|
|
||||||
|
======================================================================
|
||||||
|
2/7 手表屏幕布局适配核算 (490x602)
|
||||||
|
======================================================================
|
||||||
|
|
||||||
|
==========================================================================
|
||||||
|
通过 40 项,失败 0 项
|
||||||
|
|
||||||
|
======================================================================
|
||||||
|
1z/7 手表分页完整性(防白屏:方法定义了必须被调用)
|
||||||
|
======================================================================
|
||||||
|
sendMedia: 已被 media() 取代
|
||||||
|
showInfo: 已被 feature_run 的 info 取代
|
||||||
|
sp: 旧的字号辅助,已被 dp() 取代
|
||||||
|
|
||||||
|
==========================================================
|
||||||
|
通过 13 项,失败 0 项
|
||||||
|
|
||||||
|
======================================================================
|
||||||
|
2a2/7 APK 内容(诊断已合并进主程序)
|
||||||
|
======================================================================
|
||||||
|
通过 15 项,失败 0 项
|
||||||
|
====================================================================
|
||||||
|
|
||||||
|
======================================================================
|
||||||
|
2a/7 网络调优(MTU 修复)
|
||||||
|
======================================================================
|
||||||
|
[PASS] 写了接口 MTU 1400 更差的教训
|
||||||
|
|
||||||
|
==========================================================
|
||||||
|
通过 21 项,失败 0 项
|
||||||
|
|
||||||
|
======================================================================
|
||||||
|
2b/7 投图显示方式(屏幕中间 / 全屏 / 自定义大小)
|
||||||
|
======================================================================
|
||||||
|
==============================================================
|
||||||
|
通过 19 项,失败 0 项
|
||||||
|
截图目录: C:\Users\shu\Desktop\deepseekagent\LanRemote\_tests\shots
|
||||||
|
|
||||||
|
======================================================================
|
||||||
|
3/7 屏幕共享可见提示(真实界面 + Win32 窗口枚举)
|
||||||
|
======================================================================
|
||||||
|
|
||||||
|
====================================================================
|
||||||
|
通过 13 项,失败 0 项
|
||||||
|
|
||||||
|
======================================================================
|
||||||
|
2b/7 中转 chunked 请求体(防连接错位)
|
||||||
|
======================================================================
|
||||||
|
通过 9 项,失败 0 项
|
||||||
|
|
||||||
|
======================================================================
|
||||||
|
3a/7 局域网直连路径(不经中转)
|
||||||
|
======================================================================
|
||||||
|
通过 29 项,失败 0 项
|
||||||
|
|
||||||
|
======================================================================
|
||||||
|
3a2/7 局域网优化(网段掩码 / 发现重发 / 回切)
|
||||||
|
======================================================================
|
||||||
|
通过 42 项,失败 0 项
|
||||||
|
|
||||||
|
======================================================================
|
||||||
|
3a3/7 手表局域网切换逻辑(源码断言)
|
||||||
|
======================================================================
|
||||||
|
通过 31 项,失败 0 项
|
||||||
|
|
||||||
|
======================================================================
|
||||||
|
3a4/7 编码与换行(.java/.py 必须 UTF-8 无 BOM + LF)
|
||||||
|
======================================================================
|
||||||
|
检查 24 个文件,编码/换行全部符合约定
|
||||||
|
|
||||||
|
======================================================================
|
||||||
|
3b/7 Python 静态检查(pyflakes)
|
||||||
|
======================================================================
|
||||||
|
✓ 没有会导致崩溃的问题
|
||||||
|
|
||||||
|
======================================================================
|
||||||
|
3b3/7 安装包脚本语法(Inno 的注释陷阱)
|
||||||
|
======================================================================
|
||||||
|
[Code] 段落里没有违规写法 ✓
|
||||||
|
|
||||||
|
======================================================================
|
||||||
|
3b4/7 卸载逻辑(不能杀自己 / 不能阻塞)
|
||||||
|
======================================================================
|
||||||
|
通过 11 项,失败 0 项
|
||||||
|
|
||||||
|
======================================================================
|
||||||
|
3b2/7 管理页网络体检
|
||||||
|
======================================================================
|
||||||
|
通过 15 项,失败 0 项
|
||||||
|
|
||||||
|
======================================================================
|
||||||
|
3b5/7 安装包完整周期(装 -> 验 -> 卸 -> 再验)
|
||||||
|
======================================================================
|
||||||
|
通过 20 项,失败 0 项
|
||||||
|
|
||||||
|
======================================================================
|
||||||
|
3b6/7 网页响应头(Content-Type / HEAD)
|
||||||
|
======================================================================
|
||||||
|
通过 12 项,失败 0 项
|
||||||
|
|
||||||
|
======================================================================
|
||||||
|
3b7/7 对外材料清洁度(不许出现管理后台)
|
||||||
|
======================================================================
|
||||||
|
通过 15 项,失败 0 项
|
||||||
|
|
||||||
|
======================================================================
|
||||||
|
3c/7 中转管理端批量删除
|
||||||
|
======================================================================
|
||||||
|
通过 24 项,失败 0 项
|
||||||
|
|
||||||
|
======================================================================
|
||||||
|
3d/7 管理页 JS 合法性(防幽灵按键)
|
||||||
|
======================================================================
|
||||||
|
结论:JS 合法,删除按钮能正常工作
|
||||||
|
|
||||||
|
======================================================================
|
||||||
|
3e/7 管理页设备控制(接入开关 + 改配对码)
|
||||||
|
======================================================================
|
||||||
|
通过 23 项,失败 0 项
|
||||||
|
|
||||||
|
======================================================================
|
||||||
|
4b/7 手表 Activity 骨架(防白屏)
|
||||||
|
======================================================================
|
||||||
|
通过 24 项,失败 0 项
|
||||||
|
|
||||||
|
======================================================================
|
||||||
|
4c/7 编译整个手表 App(含界面代码)
|
||||||
|
======================================================================
|
||||||
|
App 编译通过
|
||||||
|
|
||||||
|
======================================================================
|
||||||
|
5/7 编译 Java 协议层
|
||||||
|
======================================================================
|
||||||
|
编译通过
|
||||||
|
|
||||||
|
======================================================================
|
||||||
|
6/7 Java <-> 桩服务端 跨语言联调
|
||||||
|
======================================================================
|
||||||
|
[PASS] 关闭后 isConnected 为 false
|
||||||
|
|
||||||
|
====================================================================
|
||||||
|
通过 64 项,失败 0 项
|
||||||
|
|
||||||
|
======================================================================
|
||||||
|
7/7 Java <-> 打包后的 EXE 端到端联调
|
||||||
|
======================================================================
|
||||||
|
EXE 配对码: 421865
|
||||||
|
[PASS] 关闭后 isConnected 为 false
|
||||||
|
|
||||||
|
====================================================================
|
||||||
|
通过 64 项,失败 0 项
|
||||||
|
|
||||||
|
EXE 接收到的文件:
|
||||||
|
1,024 B broken.png
|
||||||
|
307,207 B java_payload.bin
|
||||||
|
202 B java_photo.png
|
||||||
|
16,044 B java_sound.wav
|
||||||
|
|
||||||
|
======================================================================
|
||||||
|
验证汇总
|
||||||
|
======================================================================
|
||||||
|
|
||||||
|
项目 结果
|
||||||
|
-- --
|
||||||
|
编码审计 PASS
|
||||||
|
Python 被控端协议回归 PASS
|
||||||
|
防火墙阻止规则检测 PASS
|
||||||
|
自检请求链路 PASS
|
||||||
|
新增功能 PASS
|
||||||
|
电脑功能注册表 PASS
|
||||||
|
功能模糊测试 PASS
|
||||||
|
端到端(打包 EXE) PASS
|
||||||
|
静默模式 PASS
|
||||||
|
配一次→零窗口 PASS
|
||||||
|
首次设置窗口 PASS
|
||||||
|
开机零窗口 PASS
|
||||||
|
手表布局适配 PASS
|
||||||
|
手表分页完整性 PASS
|
||||||
|
APK 内容 PASS
|
||||||
|
网络调优(MTU) PASS
|
||||||
|
投图显示方式 PASS
|
||||||
|
屏幕共享强制提示 PASS
|
||||||
|
中转 chunked 请求体 PASS
|
||||||
|
局域网直连路径 PASS
|
||||||
|
局域网优化 PASS
|
||||||
|
手表局域网切换 PASS
|
||||||
|
编码与换行 PASS
|
||||||
|
Python 静态检查 PASS
|
||||||
|
安装包脚本语法 PASS
|
||||||
|
卸载逻辑 PASS
|
||||||
|
管理页网络体检 PASS
|
||||||
|
安装包完整周期 PASS
|
||||||
|
网页响应头 PASS
|
||||||
|
对外材料清洁度 PASS
|
||||||
|
中转批量删除 PASS
|
||||||
|
管理页 JS 合法性 PASS
|
||||||
|
管理页设备控制 PASS
|
||||||
|
手表 Activity 骨架 PASS
|
||||||
|
手表 App 整体编译 PASS
|
||||||
|
Java 协议层编译 PASS
|
||||||
|
Java <-> 桩服务端 PASS
|
||||||
|
Java <-> 打包 EXE PASS
|
||||||
|
|
||||||
|
|
||||||
|
全部通过
|
||||||
@@ -0,0 +1,294 @@
|
|||||||
|
|
||||||
|
======================================================================
|
||||||
|
0/7 清理残留进程与端口
|
||||||
|
======================================================================
|
||||||
|
端口干净
|
||||||
|
清掉上次测试残留的 4 个文件
|
||||||
|
|
||||||
|
======================================================================
|
||||||
|
0/7 编码审计(BOM / 行尾 / 乱码)
|
||||||
|
======================================================================
|
||||||
|
|
||||||
|
==========================================================================
|
||||||
|
鉁?鍏ㄩ儴閫氳繃锛屾病鏈夌紪鐮侀棶棰?
|
||||||
|
|
||||||
|
======================================================================
|
||||||
|
1/7 Python 被控端协议回归
|
||||||
|
======================================================================
|
||||||
|
[PASS] 绉婚櫎鍚庝粎鍓?1 鍙?
|
||||||
|
|
||||||
|
====================================================================
|
||||||
|
閫氳繃 69 椤癸紝澶辫触 0 椤?
|
||||||
|
|
||||||
|
======================================================================
|
||||||
|
1b/7 防火墙阻止规则检测(真机连不上的根因)
|
||||||
|
======================================================================
|
||||||
|
====================================================================
|
||||||
|
閫氳繃 43 椤癸紝澶辫触 0 椤?
|
||||||
|
====================================================================
|
||||||
|
|
||||||
|
======================================================================
|
||||||
|
1c/7 连不上?-> 电脑打开网络自检(UDP 链路)
|
||||||
|
======================================================================
|
||||||
|
============================================================
|
||||||
|
閫氳繃 5 椤癸紝澶辫触 0 椤?
|
||||||
|
|
||||||
|
======================================================================
|
||||||
|
1e/7 新增功能(电量/磁盘/性能/进程/剪贴板历史/安全边界)
|
||||||
|
======================================================================
|
||||||
|
==============================================================
|
||||||
|
閫氳繃 22 椤癸紝澶辫触 0 椤?
|
||||||
|
|
||||||
|
======================================================================
|
||||||
|
1f/7 电脑功能注册表(39 个功能 + 安全边界 + 可配置)
|
||||||
|
======================================================================
|
||||||
|
==============================================================
|
||||||
|
閫氳繃 29 椤癸紝澶辫触 0 椤?
|
||||||
|
|
||||||
|
======================================================================
|
||||||
|
1g/7 功能模糊测试(105 个功能 × 空参数 / 垃圾参数 / 越权路径)
|
||||||
|
======================================================================
|
||||||
|
[宕╂簝] hand_reset({}) -> FileNotFoundError: [Errno 2] No such file or directory: 'C:\\Users\\shu\\AppData\\Local\\Temp\\tmp5d758dnb\\settings.json'
|
||||||
|
[宕╂簝] lesson_timer({}) -> FileNotFoundError: [Errno 2] No such file or directory: 'C:\\Users\\shu\\AppData\\Local\\Temp\\tmp5d758dnb\\settings.json'
|
||||||
|
[宕╂簝] loop_play({}) -> FileNotFoundError: [Errno 2] No such file or directory: 'C:\\Users\\shu\\AppData\\Local\\Temp\\tmp5d758dnb\\settings.json'
|
||||||
|
|
||||||
|
======================================================================
|
||||||
|
1h/7 端到端(打包后的 EXE:配对 / 功能列表 / 越权 / 防爆破)
|
||||||
|
======================================================================
|
||||||
|
|
||||||
|
==============================================================
|
||||||
|
閫氳繃 13 椤癸紝澶辫触 0 椤?
|
||||||
|
|
||||||
|
======================================================================
|
||||||
|
1i/7 静默模式(0 窗口 / 无终端 / 认证仍生效)
|
||||||
|
======================================================================
|
||||||
|
|
||||||
|
==============================================================
|
||||||
|
閫氳繃 8 椤癸紝澶辫触 0 椤?
|
||||||
|
|
||||||
|
======================================================================
|
||||||
|
1j/7 配一次→零窗口(令牌重连,全程无窗口)
|
||||||
|
======================================================================
|
||||||
|
|
||||||
|
==============================================================
|
||||||
|
閫氳繃 12 椤癸紝澶辫触 0 椤?
|
||||||
|
|
||||||
|
======================================================================
|
||||||
|
1k/7 首次安装设置窗口(出现一次,之后不再出现)
|
||||||
|
======================================================================
|
||||||
|
|
||||||
|
==============================================================
|
||||||
|
閫氳繃 14 椤癸紝澶辫触 0 椤?
|
||||||
|
|
||||||
|
======================================================================
|
||||||
|
1l/7 开机零窗口(照注册表里的自启命令真跑一遍)
|
||||||
|
======================================================================
|
||||||
|
|
||||||
|
==============================================================
|
||||||
|
閫氳繃 7 椤癸紝澶辫触 0 椤?
|
||||||
|
|
||||||
|
======================================================================
|
||||||
|
2/7 手表屏幕布局适配核算 (490x602)
|
||||||
|
======================================================================
|
||||||
|
|
||||||
|
==========================================================================
|
||||||
|
閫氳繃 40 椤癸紝澶辫触 0 椤?
|
||||||
|
|
||||||
|
======================================================================
|
||||||
|
1z/7 手表分页完整性(防白屏:方法定义了必须被调用)
|
||||||
|
======================================================================
|
||||||
|
sendMedia: 宸茶� media() 鍙栦唬
|
||||||
|
showInfo: 宸茶� feature_run 鐨?info 鍙栦唬
|
||||||
|
sp: 鏃х殑瀛楀彿杈呭姪锛屽凡琚?dp() 鍙栦唬
|
||||||
|
|
||||||
|
==========================================================
|
||||||
|
閫氳繃 13 椤癸紝澶辫触 0 椤?
|
||||||
|
|
||||||
|
======================================================================
|
||||||
|
2a2/7 APK 内容(诊断已合并进主程序)
|
||||||
|
======================================================================
|
||||||
|
閫氳繃 15 椤癸紝澶辫触 0 椤?
|
||||||
|
====================================================================
|
||||||
|
|
||||||
|
======================================================================
|
||||||
|
2a/7 网络调优(MTU 修复)
|
||||||
|
======================================================================
|
||||||
|
[PASS] 鍐欎簡鎺ュ彛 MTU 1400 鏇村樊鐨勬暀璁?
|
||||||
|
|
||||||
|
==========================================================
|
||||||
|
閫氳繃 20 椤癸紝澶辫触 1 椤?
|
||||||
|
|
||||||
|
======================================================================
|
||||||
|
2b/7 投图显示方式(屏幕中间 / 全屏 / 自定义大小)
|
||||||
|
======================================================================
|
||||||
|
==============================================================
|
||||||
|
閫氳繃 19 椤癸紝澶辫触 0 椤?
|
||||||
|
鎴�浘鐩�綍: C:\Users\shu\Desktop\deepseekagent\LanRemote\_tests\shots
|
||||||
|
|
||||||
|
======================================================================
|
||||||
|
3/7 屏幕共享可见提示(真实界面 + Win32 窗口枚举)
|
||||||
|
======================================================================
|
||||||
|
|
||||||
|
====================================================================
|
||||||
|
閫氳繃 13 椤癸紝澶辫触 0 椤?
|
||||||
|
|
||||||
|
======================================================================
|
||||||
|
2b/7 中转 chunked 请求体(防连接错位)
|
||||||
|
======================================================================
|
||||||
|
閫氳繃 9 椤癸紝澶辫触 0 椤?
|
||||||
|
|
||||||
|
======================================================================
|
||||||
|
3a/7 局域网直连路径(不经中转)
|
||||||
|
======================================================================
|
||||||
|
閫氳繃 29 椤癸紝澶辫触 0 椤?
|
||||||
|
|
||||||
|
======================================================================
|
||||||
|
3a2/7 局域网优化(网段掩码 / 发现重发 / 回切)
|
||||||
|
======================================================================
|
||||||
|
閫氳繃 42 椤癸紝澶辫触 0 椤?
|
||||||
|
|
||||||
|
======================================================================
|
||||||
|
3a3/7 手表局域网切换逻辑(源码断言)
|
||||||
|
======================================================================
|
||||||
|
閫氳繃 31 椤癸紝澶辫触 0 椤?
|
||||||
|
|
||||||
|
======================================================================
|
||||||
|
3a4/7 编码与换行(.java/.py 必须 UTF-8 无 BOM + LF)
|
||||||
|
======================================================================
|
||||||
|
妫€鏌?24 涓�枃浠讹紝缂栫爜/鎹㈣�鍏ㄩ儴绗﹀悎绾﹀畾
|
||||||
|
|
||||||
|
======================================================================
|
||||||
|
3b/7 Python 静态检查(pyflakes)
|
||||||
|
======================================================================
|
||||||
|
鉁?娌℃湁浼氬�鑷村穿婧冪殑闂��
|
||||||
|
|
||||||
|
======================================================================
|
||||||
|
3b3/7 安装包脚本语法(Inno 的注释陷阱)
|
||||||
|
======================================================================
|
||||||
|
[Code] 娈佃惤閲屾病鏈夎繚瑙勫啓娉?鉁?
|
||||||
|
|
||||||
|
======================================================================
|
||||||
|
3b4/7 卸载逻辑(不能杀自己 / 不能阻塞)
|
||||||
|
======================================================================
|
||||||
|
閫氳繃 11 椤癸紝澶辫触 0 椤?
|
||||||
|
|
||||||
|
======================================================================
|
||||||
|
3b2/7 管理页网络体检
|
||||||
|
======================================================================
|
||||||
|
閫氳繃 15 椤癸紝澶辫触 0 椤?
|
||||||
|
|
||||||
|
======================================================================
|
||||||
|
3b5/7 安装包完整周期(装 -> 验 -> 卸 -> 再验)
|
||||||
|
======================================================================
|
||||||
|
閫氳繃 20 椤癸紝澶辫触 0 椤?
|
||||||
|
|
||||||
|
======================================================================
|
||||||
|
3b6/7 网页响应头(Content-Type / HEAD)
|
||||||
|
======================================================================
|
||||||
|
閫氳繃 12 椤癸紝澶辫触 0 椤?
|
||||||
|
|
||||||
|
======================================================================
|
||||||
|
3b7/7 对外材料清洁度(不许出现管理后台)
|
||||||
|
======================================================================
|
||||||
|
閫氳繃 15 椤癸紝澶辫触 0 椤?
|
||||||
|
|
||||||
|
======================================================================
|
||||||
|
3c/7 中转管理端批量删除
|
||||||
|
======================================================================
|
||||||
|
閫氳繃 24 椤癸紝澶辫触 0 椤?
|
||||||
|
|
||||||
|
======================================================================
|
||||||
|
3d/7 管理页 JS 合法性(防幽灵按键)
|
||||||
|
======================================================================
|
||||||
|
缁撹�锛欽S 鍚堟硶锛屽垹闄ゆ寜閽�兘姝e父宸ヤ綔
|
||||||
|
|
||||||
|
======================================================================
|
||||||
|
3e/7 管理页设备控制(接入开关 + 改配对码)
|
||||||
|
======================================================================
|
||||||
|
閫氳繃 23 椤癸紝澶辫触 0 椤?
|
||||||
|
|
||||||
|
======================================================================
|
||||||
|
4b/7 手表 Activity 骨架(防白屏)
|
||||||
|
======================================================================
|
||||||
|
閫氳繃 24 椤癸紝澶辫触 0 椤?
|
||||||
|
|
||||||
|
======================================================================
|
||||||
|
4c/7 编译整个手表 App(含界面代码)
|
||||||
|
======================================================================
|
||||||
|
App 编译通过
|
||||||
|
|
||||||
|
======================================================================
|
||||||
|
5/7 编译 Java 协议层
|
||||||
|
======================================================================
|
||||||
|
编译通过
|
||||||
|
|
||||||
|
======================================================================
|
||||||
|
6/7 Java <-> 桩服务端 跨语言联调
|
||||||
|
======================================================================
|
||||||
|
[PASS] 鍏抽棴鍚?isConnected 涓?false
|
||||||
|
|
||||||
|
====================================================================
|
||||||
|
閫氳繃 64 椤癸紝澶辫触 0 椤?
|
||||||
|
|
||||||
|
======================================================================
|
||||||
|
7/7 Java <-> 打包后的 EXE 端到端联调
|
||||||
|
======================================================================
|
||||||
|
EXE 配对码: 193406
|
||||||
|
[PASS] 鍏抽棴鍚?isConnected 涓?false
|
||||||
|
|
||||||
|
====================================================================
|
||||||
|
閫氳繃 64 椤癸紝澶辫触 0 椤?
|
||||||
|
|
||||||
|
EXE 接收到的文件:
|
||||||
|
1,024 B broken.png
|
||||||
|
307,207 B java_payload.bin
|
||||||
|
202 B java_photo.png
|
||||||
|
16,044 B java_sound.wav
|
||||||
|
|
||||||
|
======================================================================
|
||||||
|
验证汇总
|
||||||
|
======================================================================
|
||||||
|
|
||||||
|
项目 结果
|
||||||
|
---- ----
|
||||||
|
编码审计 PASS
|
||||||
|
Python 被控端协议回归 PASS
|
||||||
|
防火墙阻止规则检测 PASS
|
||||||
|
自检请求链路 PASS
|
||||||
|
新增功能 PASS
|
||||||
|
电脑功能注册表 PASS
|
||||||
|
功能模糊测试 PASS
|
||||||
|
端到端(打包 EXE) PASS
|
||||||
|
静默模式 PASS
|
||||||
|
配一次→零窗口 PASS
|
||||||
|
首次设置窗口 PASS
|
||||||
|
开机零窗口 PASS
|
||||||
|
手表布局适配 PASS
|
||||||
|
手表分页完整性 PASS
|
||||||
|
APK 内容 PASS
|
||||||
|
网络调优(MTU) FAIL
|
||||||
|
投图显示方式 PASS
|
||||||
|
屏幕共享强制提示 PASS
|
||||||
|
中转 chunked 请求体 PASS
|
||||||
|
局域网直连路径 PASS
|
||||||
|
局域网优化 PASS
|
||||||
|
手表局域网切换 PASS
|
||||||
|
编码与换行 PASS
|
||||||
|
Python 静态检查 PASS
|
||||||
|
安装包脚本语法 PASS
|
||||||
|
卸载逻辑 PASS
|
||||||
|
管理页网络体检 PASS
|
||||||
|
安装包完整周期 PASS
|
||||||
|
网页响应头 PASS
|
||||||
|
对外材料清洁度 PASS
|
||||||
|
中转批量删除 PASS
|
||||||
|
管理页 JS 合法性 PASS
|
||||||
|
管理页设备控制 PASS
|
||||||
|
手表 Activity 骨架 PASS
|
||||||
|
手表 App 整体编译 PASS
|
||||||
|
Java 协议层编译 PASS
|
||||||
|
Java <-> 桩服务端 PASS
|
||||||
|
Java <-> 打包 EXE PASS
|
||||||
|
|
||||||
|
|
||||||
|
项失败
|
||||||
+116
-2
@@ -85,7 +85,82 @@ QUIC 建齐 6 条连接 28 秒 -> 13 秒
|
|||||||
dial 失败次数 2 -> 1
|
dial 失败次数 2 -> 1
|
||||||
```
|
```
|
||||||
|
|
||||||
### 2.4 异常长轮询(126 秒)是隧道重启造成的
|
### 2.5 周期性 QUIC 崩溃:每 8~10 分钟一次
|
||||||
|
|
||||||
|
长测期间观察到一个反复出现的模式:**QUIC 的连接数会突然从 8 掉到 1,几秒后又回到 8。**
|
||||||
|
|
||||||
|
连接数采样(每 60 秒)里抓到的几个瞬间:
|
||||||
|
|
||||||
|
```
|
||||||
|
17:30:53 quic=7 h2=2
|
||||||
|
17:31:59 quic=1 h2=2 <- QUIC 塌了
|
||||||
|
17:33:04 quic=8 h2=2 <- 自己回来了
|
||||||
|
...
|
||||||
|
17:55:33 quic=8 h2=2
|
||||||
|
17:57:06 quic=1 h2=2 <- 又塌
|
||||||
|
17:58:12 quic=8 h2=2
|
||||||
|
```
|
||||||
|
|
||||||
|
**关键观察:QUIC 塌到 1 条时,HTTP/2 那 2 条始终存活。**
|
||||||
|
|
||||||
|
也就是说:
|
||||||
|
* 这是**链路级**的突发事件(不是单条连接的问题),QUIC 对它特别敏感
|
||||||
|
* 而 HTTP/2 over TCP 靠内核的 SYN/重传扛住了
|
||||||
|
|
||||||
|
watchdog 日志同时段记录:
|
||||||
|
|
||||||
|
```
|
||||||
|
17:56:39 公网不通(HTTP 000,quic=1, h2=2) 连续第 1 次
|
||||||
|
17:56:59 公网不通(HTTP 000,quic=7, h2=2) 连续第 2 次 <- 自己回来了
|
||||||
|
17:57:09 公网不通(HTTP 502,quic=6, h2=2) 连续第 3 次
|
||||||
|
17:57:09 公网连续 3 次不通,但连接健康(合计 8 条)—— 再等等,不重启
|
||||||
|
17:57:11 公网不通(HTTP 502,quic=1, h2=1) 连续第 4 次 <- 又塌,且 h2 也掉了
|
||||||
|
17:57:11 连续 4 次公网不通 —— 重启 [两个实例]
|
||||||
|
17:57:37 本次已建齐(合计 10 条) <- 26 秒恢复
|
||||||
|
```
|
||||||
|
|
||||||
|
**这次重启是对的**:连接总数掉到 2 条,属于确认故障。
|
||||||
|
而且**重启把中断缩短到 26 秒** —— 比等 QUIC 自然恢复(可能要几分钟)更划算。
|
||||||
|
|
||||||
|
**一个值得后续验证的改进方向**:
|
||||||
|
QUIC 塌掉时只剩 http2=2 在扛,容量很薄。把 HTTP/2 从 2 条提到 4 条,
|
||||||
|
可能能在这种窗口里多撑一会儿。但注意第 2.2 节的配比对照是
|
||||||
|
**2 分钟的短样本**,抓不到这种 9 分钟周期的事件 —— 要验证得跑更长的对照。
|
||||||
|
|
||||||
|
### 2.6 故障不集中在某个时段
|
||||||
|
|
||||||
|
把 watchdog 记录的"公网不通"按小时分桶,全天分布是均匀的,
|
||||||
|
**没有出现"运营商某时段抖动"的特征**:
|
||||||
|
|
||||||
|
```
|
||||||
|
16:14 / 16:21 / 16:22 / 16:30 / 16:34 / 16:40 / 16:41 / 16:42
|
||||||
|
16:49 / 16:50 / 17:00 / 17:10 / 17:11 / 17:12 / 17:13 ...
|
||||||
|
```
|
||||||
|
|
||||||
|
多数是 1 秒内自愈(`公网不通` 紧接着 `公网恢复`)。
|
||||||
|
真正造成可见中断的只有三次:
|
||||||
|
|
||||||
|
```
|
||||||
|
16:30:19 -> 16:34:28 (4 分 09 秒)
|
||||||
|
16:50:39 -> 16:53:04 (2 分 25 秒)
|
||||||
|
17:00:20 -> 17:02:27 (2 分 07 秒)
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2.7 客户端与设备同时故障 = 源站侧问题
|
||||||
|
|
||||||
|
PC 侧长测(WiFi/宽带,与设备完全不同的网络)在同一个窗口也失败了:
|
||||||
|
|
||||||
|
```
|
||||||
|
PC 侧: 17:56:57 code=0 42093ms
|
||||||
|
17:57:13 code=502 674ms
|
||||||
|
17:58:57 code=0 25818ms
|
||||||
|
|
||||||
|
设备侧: 17:56:46 code=000 25000ms
|
||||||
|
17:57:06 code=502 4652ms
|
||||||
|
```
|
||||||
|
|
||||||
|
**两个独立网络同时受影响,说明问题在 Cloudflare 边缘或隧道这一侧,
|
||||||
|
不是某一端的本地链路。**
|
||||||
|
|
||||||
30 次长轮询里出现两次 ~126.7 秒(正好是 2 倍 hold + 开销):
|
30 次长轮询里出现两次 ~126.7 秒(正好是 2 倍 hold + 开销):
|
||||||
|
|
||||||
@@ -152,7 +227,46 @@ dial 失败次数 2 -> 1
|
|||||||
|
|
||||||
## 四、实测数据
|
## 四、实测数据
|
||||||
|
|
||||||
(待 2 小时长测结束后填入)
|
### 4.1 长轮询:30 次真实 poll(每次挂 60 秒)
|
||||||
|
|
||||||
|
```
|
||||||
|
成功 29/30 = 96%
|
||||||
|
失败 #22(000,130001ms —— 撞上 17:57 那次隧道重启,客户端 130 秒超时)
|
||||||
|
|
||||||
|
耗时分布(成功的):
|
||||||
|
最小 60920 P50 61439 P90 126604 P99 126716 最大 126716 ms
|
||||||
|
理想值 = 60000 + 隧道开销 ≈ 61000
|
||||||
|
```
|
||||||
|
|
||||||
|
**分布是双峰的**:
|
||||||
|
|
||||||
|
| 档位 | 次数 | 说明 |
|
||||||
|
|---|---|---|
|
||||||
|
| 61 秒 | 26 | 正常,开销只有 1~1.5 秒 |
|
||||||
|
| 126 秒 | 3 | 约 2 倍 hold,**全部对齐到隧道重启窗口** |
|
||||||
|
|
||||||
|
对照三次异常的时间线:
|
||||||
|
|
||||||
|
```
|
||||||
|
#1 17:30:42 开始 -> 17:31:40 watchdog 重启两个实例 -> 126604ms
|
||||||
|
#10 17:40:59 开始 -> 17:41:56 公网 000、17:42:46 重启 h2 -> 126716ms
|
||||||
|
#18 17:50:17 开始 -> 17:50:42~17:51:25 连续三次不通 -> 126363ms
|
||||||
|
#22 17:55:28 开始 -> 17:57:11 重启两个实例 -> 超时 130001ms
|
||||||
|
```
|
||||||
|
|
||||||
|
**结论:稳态下长轮询极其干净(61~62 秒,抖动 < 2 秒);
|
||||||
|
126 秒那种是隧道被重启打断造成的,不是协议或中转的问题。**
|
||||||
|
|
||||||
|
### 4.2 设备侧公网可用率(2 小时长测,每 15 秒一次)
|
||||||
|
|
||||||
|
数据见第 4.4 节的最终汇总。
|
||||||
|
|
||||||
|
### 4.3 PC 侧(真实用户视角)
|
||||||
|
|
||||||
|
PC(WiFi/宽带)发起,只有"边缘 -> 隧道 -> 设备 4G"这一跳是慢的。
|
||||||
|
这与真实用户的情况一致(用户也是好网络)。
|
||||||
|
|
||||||
|
### 4.4 待 2 小时长测结束后填入
|
||||||
|
|
||||||
## 五、受链路物理条件限制、做不到 100% 的部分
|
## 五、受链路物理条件限制、做不到 100% 的部分
|
||||||
|
|
||||||
|
|||||||
@@ -86,3 +86,46 @@ time code ms
|
|||||||
2026-10-07 17:54:08 200 844
|
2026-10-07 17:54:08 200 844
|
||||||
2026-10-07 17:54:24 200 775
|
2026-10-07 17:54:24 200 775
|
||||||
2026-10-07 17:54:40 200 830
|
2026-10-07 17:54:40 200 830
|
||||||
|
2026-10-07 17:54:56 200 849
|
||||||
|
2026-10-07 17:55:12 200 1329
|
||||||
|
2026-10-07 17:55:28 200 836
|
||||||
|
2026-10-07 17:55:44 200 779
|
||||||
|
2026-10-07 17:56:00 200 884
|
||||||
|
2026-10-07 17:56:57 0 42093
|
||||||
|
2026-10-07 17:57:13 502 674
|
||||||
|
2026-10-07 17:57:28 200 756
|
||||||
|
2026-10-07 17:57:44 200 700
|
||||||
|
2026-10-07 17:58:00 200 831
|
||||||
|
2026-10-07 17:58:16 200 1551
|
||||||
|
2026-10-07 17:58:57 0 25818
|
||||||
|
2026-10-07 17:59:13 200 794
|
||||||
|
2026-10-07 17:59:29 200 880
|
||||||
|
2026-10-07 17:59:45 200 792
|
||||||
|
2026-10-07 18:00:02 200 1894
|
||||||
|
2026-10-07 18:00:39 200 22561
|
||||||
|
2026-10-07 18:01:17 200 22565
|
||||||
|
2026-10-07 18:01:54 200 22281
|
||||||
|
2026-10-07 18:02:31 200 22183
|
||||||
|
2026-10-07 18:03:02 200 16014
|
||||||
|
2026-10-07 18:03:18 200 890
|
||||||
|
2026-10-07 18:03:34 200 805
|
||||||
|
2026-10-07 18:03:50 200 844
|
||||||
|
2026-10-07 18:04:06 200 851
|
||||||
|
2026-10-07 18:04:21 200 688
|
||||||
|
2026-10-07 18:04:37 200 920
|
||||||
|
2026-10-07 18:04:53 200 908
|
||||||
|
2026-10-07 18:05:09 200 841
|
||||||
|
2026-10-07 18:05:25 200 896
|
||||||
|
2026-10-07 18:05:41 200 1008
|
||||||
|
2026-10-07 18:05:56 200 654
|
||||||
|
2026-10-07 18:06:12 200 829
|
||||||
|
2026-10-07 18:06:28 200 777
|
||||||
|
2026-10-07 18:06:44 200 866
|
||||||
|
2026-10-07 18:07:00 200 1003
|
||||||
|
2026-10-07 18:07:16 200 815
|
||||||
|
2026-10-07 18:07:32 200 748
|
||||||
|
2026-10-07 18:07:47 200 802
|
||||||
|
2026-10-07 18:08:04 200 1272
|
||||||
|
2026-10-07 18:08:20 200 1260
|
||||||
|
2026-10-07 18:08:36 200 1009
|
||||||
|
2026-10-07 18:08:52 200 1104
|
||||||
|
|||||||
|
@@ -0,0 +1,48 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# 分析"每 9 分钟一次异常"的周期性 —— 到底是谁在定期动手
|
||||||
|
set -u
|
||||||
|
|
||||||
|
echo "════════ 1. 异常轮询的时刻 ════════"
|
||||||
|
awk -F'\t' '$3>90000 || $2!="200" {print " #" $1 " " $4 " 码=" $2 " " $3 "ms"}' \
|
||||||
|
/root/rp_poll30.tsv 2>/dev/null
|
||||||
|
|
||||||
|
echo
|
||||||
|
echo "════════ 2. 连接数掉到 3 以下的时刻(全量)════════"
|
||||||
|
awk -F'\t' 'NR>1 && $2 ~ /^[0-9]+$/ && $3 ~ /^[0-9]+$/ && ($2+$3)<4 {
|
||||||
|
print " " $1 " quic=" $2 " http2=" $3
|
||||||
|
}' /root/long2h_conns.tsv 2>/dev/null
|
||||||
|
|
||||||
|
echo
|
||||||
|
echo "════════ 3. 这些时刻前后 watchdog 做了什么 ════════"
|
||||||
|
tail -40 /root/lanremote-relay/watchdog.log 2>/dev/null | sed 's/^/ /'
|
||||||
|
|
||||||
|
echo
|
||||||
|
echo "════════ 4. QUIC 实例的连接事件(最近 40 条)════════"
|
||||||
|
grep -E 'Registered|Lost|Unregistered' /root/lanremote-relay/tunnel.log 2>/dev/null \
|
||||||
|
| tail -40 | sed -E 's/^(....-..-..T..:..):[0-9]+Z .*(Registered tunnel connection|Lost connection|Unregistered).*ip=([0-9.]+).*location=([a-z0-9]+).*/\1 \2 \3 \4/' \
|
||||||
|
| sed 's/^/ /'
|
||||||
|
|
||||||
|
echo
|
||||||
|
echo "════════ 5. 有没有周期性(看事件间隔)════════"
|
||||||
|
echo " 最近 20 次 Lost connection 的时间:"
|
||||||
|
grep 'Lost connection' /root/lanremote-relay/tunnel.log 2>/dev/null \
|
||||||
|
| tail -20 | cut -c1-19 | sed 's/^/ /'
|
||||||
|
|
||||||
|
echo
|
||||||
|
echo "════════ 6. 线程/进程层面:cloudflared 有没有重启过 ════════"
|
||||||
|
echo " QUIC 实例进程启动时间: $(ps -o lstart= -p $(pgrep -f 'protocol quic' | head -1) 2>/dev/null)"
|
||||||
|
echo " HTTP/2 实例进程启动时间: $(ps -o lstart= -p $(pgrep -f 'protocol http2' | head -1) 2>/dev/null)"
|
||||||
|
echo " QUIC 服务重启次数(本次开机以来):"
|
||||||
|
journalctl -u lanremote-tunnel --since '2 hours ago' --no-pager 2>/dev/null \
|
||||||
|
| grep -c 'Starting\|Stopped' | sed 's/^/ /'
|
||||||
|
|
||||||
|
echo
|
||||||
|
echo "════════ 7. 系统层面有没有定期任务 ════════"
|
||||||
|
echo " systemd timer:"
|
||||||
|
systemctl list-timers --no-pager 2>/dev/null | head -12 | sed 's/^/ /'
|
||||||
|
echo " cron:"
|
||||||
|
crontab -l 2>/dev/null | grep -v '^#' | sed 's/^/ /' || echo " (空)"
|
||||||
|
|
||||||
|
echo
|
||||||
|
echo "════════ 8. 连接数变化明细(最近 30 条采样)════════"
|
||||||
|
tail -30 /root/long2h_conns.tsv 2>/dev/null | sed 's/^/ /'
|
||||||
@@ -0,0 +1,48 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
r'''等 2 小时长测跑完,中途定期报告进度。
|
||||||
|
|
||||||
|
用法: python _build/rp_wait.py [总等待秒数] [检查间隔秒数]
|
||||||
|
'''
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import sys
|
||||||
|
import time
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
sys.path.insert(0, str(Path(__file__).parent))
|
||||||
|
|
||||||
|
from devssh import run # noqa: E402
|
||||||
|
|
||||||
|
|
||||||
|
def once(label: str) -> None:
|
||||||
|
out = run("bash /root/rppg.sh 2>&1", timeout=300)[1]
|
||||||
|
print(" ────── %s ──────" % label)
|
||||||
|
# 只留关键行
|
||||||
|
for line in out.splitlines():
|
||||||
|
s = line.strip()
|
||||||
|
if not s:
|
||||||
|
continue
|
||||||
|
if any(k in s for k in ("样本数", "已完成", "状态码", "最近 3 条",
|
||||||
|
"非 200", "时间", "测试进程", "rp_long2h",
|
||||||
|
"rpp30", "200", "000", "502", "530",
|
||||||
|
"quic=", "http2=", "明细", "输出日志")):
|
||||||
|
print(" " + s)
|
||||||
|
print()
|
||||||
|
|
||||||
|
|
||||||
|
def main() -> int:
|
||||||
|
total = int(sys.argv[1]) if len(sys.argv) > 1 else 3600
|
||||||
|
every = int(sys.argv[2]) if len(sys.argv) > 2 else 900
|
||||||
|
waited = 0
|
||||||
|
n = 0
|
||||||
|
while waited < total:
|
||||||
|
step = min(every, total - waited)
|
||||||
|
time.sleep(step)
|
||||||
|
waited += step
|
||||||
|
n += 1
|
||||||
|
once("检查点 %d(已等 %d 分钟)" % (n, waited // 60))
|
||||||
|
return 0
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
sys.exit(main())
|
||||||
@@ -0,0 +1,51 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# 看 watchdog 到底按什么节奏在重启,以及是不是过度重启
|
||||||
|
set -u
|
||||||
|
|
||||||
|
echo "════════ 1. watchdog 最近 30 行 ════════"
|
||||||
|
tail -30 /root/lanremote-relay/watchdog.log 2>/dev/null | sed 's/^/ /'
|
||||||
|
|
||||||
|
echo
|
||||||
|
echo "════════ 2. 本次开机以来所有"重启隧道"记录 ════════"
|
||||||
|
grep -E '重启 \[' /root/lanremote-relay/watchdog.log 2>/dev/null | tail -25 | sed 's/^/ /'
|
||||||
|
|
||||||
|
echo
|
||||||
|
echo "════════ 3. 重启的间隔(判断是不是过频)════════"
|
||||||
|
grep -E '重启 \[' /root/lanremote-relay/watchdog.log 2>/dev/null \
|
||||||
|
| grep -oE '^\[[0-9-]+ [0-9:]+' | sed 's/\[//' \
|
||||||
|
| awk '{
|
||||||
|
cmd = "date -d \"" $0 "\" +%s"
|
||||||
|
cmd | getline ts; close(cmd)
|
||||||
|
if (prev) printf " %s (+%d 秒)\n", $0, ts - prev
|
||||||
|
else printf " %s\n", $0
|
||||||
|
prev = ts
|
||||||
|
}' | tail -25
|
||||||
|
|
||||||
|
echo
|
||||||
|
echo "════════ 4. 每次重启的原因分类 ════════"
|
||||||
|
grep -E '重启 \[' /root/lanremote-relay/watchdog.log 2>/dev/null \
|
||||||
|
| sed -E 's/^\[[0-9-]+ [0-9:]+\] //' \
|
||||||
|
| sed -E 's/(距上次 [0-9]+ 秒)//' \
|
||||||
|
| sed -E 's/\|/ | /g' \
|
||||||
|
| awk -F'——' '{print $1}' | sed 's/[0-9]\+ 次/N 次/' \
|
||||||
|
| sort | uniq -c | sort -rn | head -12 | sed 's/^/ /'
|
||||||
|
|
||||||
|
echo
|
||||||
|
echo "════════ 5. 服务重启计数(systemd 层面)════════"
|
||||||
|
for svc in lanremote-tunnel lanremote-tunnel-h2; do
|
||||||
|
n=$(journalctl -u "$svc" --since '3 hours ago' --no-pager 2>/dev/null | grep -c 'Starting')
|
||||||
|
echo " $svc 最近 3 小时启动 $n 次"
|
||||||
|
done
|
||||||
|
|
||||||
|
echo
|
||||||
|
echo "════════ 6. 最近 1 小时的完整 watchdog 活动 ════════"
|
||||||
|
awk '/\[10-07 (1[78]):/' /root/lanremote-relay/watchdog.log 2>/dev/null | tail -25 | sed 's/^/ /'
|
||||||
|
|
||||||
|
echo
|
||||||
|
echo "════════ 7. 当前状态 ════════"
|
||||||
|
echo " watchdog: $(systemctl is-active lanremote-watchdog.timer)"
|
||||||
|
echo " 状态文件: $(cat /root/lanremote-relay/watchdog.state 2>/dev/null | tr '\n' ' ')"
|
||||||
|
echo " 上次重启: $(date -d @$(cat /root/lanremote-relay/watchdog.last_restart 2>/dev/null || echo 0) '+%Y-%m-%d %H:%M:%S' 2>/dev/null)"
|
||||||
|
echo " 现在: $(date '+%Y-%m-%d %H:%M:%S')"
|
||||||
|
echo " 连接数: quic=$(curl -s --max-time 4 http://127.0.0.1:20241/metrics 2>/dev/null | grep ha_connections | awk '{print $2}') http2=$(curl -s --max-time 4 http://127.0.0.1:20242/metrics 2>/dev/null | grep ha_connections | awk '{print $2}')"
|
||||||
|
echo " 长测进度: 健康 $(wc -l < /root/long2h_health.tsv) 条, 轮询 $(wc -l < /root/rp_poll30.tsv) / 30"
|
||||||
@@ -46,16 +46,28 @@ echo " bash: $(bash --version | head -1)"
|
|||||||
# ────────────────────────────────────────────────────────────
|
# ────────────────────────────────────────────────────────────
|
||||||
echo
|
echo
|
||||||
echo "── 0. 先记录线上现状(测完要确认没被碰过)──"
|
echo "── 0. 先记录线上现状(测完要确认没被碰过)──"
|
||||||
LIVE_RELAY_ACTIVE=$(systemctl is-active lanremote-relay 2>/dev/null || echo "?")
|
# ⚠ 必须用**绝对路径**抓真实命令。
|
||||||
LIVE_TUNNEL_ACTIVE=$(systemctl is-active lanremote-tunnel 2>/dev/null || echo "?")
|
# 后面会把桩目录插到 PATH 最前面,那时 `systemctl` / `iptables`
|
||||||
|
# 就都变成桩了;如果第 8 节还按名字调用,比的就是
|
||||||
|
# "真实系统 vs 桩",必然对不上(真踩过)。
|
||||||
|
REAL_SYSTEMCTL=$(command -v systemctl 2>/dev/null || echo systemctl)
|
||||||
|
REAL_IPTABLES=$(command -v iptables 2>/dev/null || echo iptables)
|
||||||
|
echo " 真实 systemctl: $REAL_SYSTEMCTL"
|
||||||
|
echo " 真实 iptables: $REAL_IPTABLES"
|
||||||
|
|
||||||
|
LIVE_RELAY_ACTIVE=$("$REAL_SYSTEMCTL" is-active lanremote-relay 2>/dev/null | head -1 || echo "?")
|
||||||
|
LIVE_TUNNEL_ACTIVE=$("$REAL_SYSTEMCTL" is-active lanremote-tunnel 2>/dev/null | head -1 || echo "?")
|
||||||
|
LIVE_TUNNEL2_ACTIVE=$("$REAL_SYSTEMCTL" is-active lanremote-tunnel-h2 2>/dev/null | head -1 || echo "?")
|
||||||
LIVE_MTU=$(cat /sys/class/net/wlan0/mtu 2>/dev/null || echo "?")
|
LIVE_MTU=$(cat /sys/class/net/wlan0/mtu 2>/dev/null || echo "?")
|
||||||
LIVE_MSS=$(iptables -t mangle -S OUTPUT 2>/dev/null | grep -c TCPMSS || echo 0)
|
LIVE_MSS=$(("$REAL_IPTABLES" -t mangle -S OUTPUT 2>/dev/null || true) | grep -c TCPMSS | head -1)
|
||||||
|
LIVE_MSS=${LIVE_MSS:-0}
|
||||||
LIVE_KEEPALIVE=$(cat /proc/sys/net/ipv4/tcp_keepalive_time 2>/dev/null || echo "?")
|
LIVE_KEEPALIVE=$(cat /proc/sys/net/ipv4/tcp_keepalive_time 2>/dev/null || echo "?")
|
||||||
echo " lanremote-relay = $LIVE_RELAY_ACTIVE"
|
echo " lanremote-relay = $LIVE_RELAY_ACTIVE"
|
||||||
echo " lanremote-tunnel = $LIVE_TUNNEL_ACTIVE"
|
echo " lanremote-tunnel = $LIVE_TUNNEL_ACTIVE"
|
||||||
echo " wlan0 MTU = $LIVE_MTU"
|
echo " lanremote-tunnel-h2 = $LIVE_TUNNEL2_ACTIVE"
|
||||||
echo " MSS 规则数 = $LIVE_MSS"
|
echo " wlan0 MTU = $LIVE_MTU"
|
||||||
echo " keepalive_time = $LIVE_KEEPALIVE"
|
echo " MSS 规则数 = $LIVE_MSS"
|
||||||
|
echo " keepalive_time = $LIVE_KEEPALIVE"
|
||||||
|
|
||||||
# ────────────────────────────────────────────────────────────
|
# ────────────────────────────────────────────────────────────
|
||||||
echo
|
echo
|
||||||
@@ -258,17 +270,21 @@ fi
|
|||||||
|
|
||||||
# ────────────────────────────────────────────────────────────
|
# ────────────────────────────────────────────────────────────
|
||||||
echo
|
echo
|
||||||
echo "── 8. 确认线上环境一点没被碰 ──"
|
echo "── 8. 确认线上环境一点没被碰(用真实命令查,不用桩)──"
|
||||||
NOW_RELAY=$(systemctl is-active lanremote-relay 2>/dev/null || echo "?")
|
NOW_RELAY=$("$REAL_SYSTEMCTL" is-active lanremote-relay 2>/dev/null | head -1 || echo "?")
|
||||||
NOW_TUNNEL=$(systemctl is-active lanremote-tunnel 2>/dev/null || echo "?")
|
NOW_TUNNEL=$("$REAL_SYSTEMCTL" is-active lanremote-tunnel 2>/dev/null | head -1 || echo "?")
|
||||||
|
NOW_TUNNEL2=$("$REAL_SYSTEMCTL" is-active lanremote-tunnel-h2 2>/dev/null | head -1 || echo "?")
|
||||||
NOW_MTU=$(cat /sys/class/net/wlan0/mtu 2>/dev/null || echo "?")
|
NOW_MTU=$(cat /sys/class/net/wlan0/mtu 2>/dev/null || echo "?")
|
||||||
NOW_MSS=$(iptables -t mangle -S OUTPUT 2>/dev/null | grep -c TCPMSS || echo 0)
|
NOW_MSS=$(("$REAL_IPTABLES" -t mangle -S OUTPUT 2>/dev/null || true) | grep -c TCPMSS | head -1)
|
||||||
|
NOW_MSS=${NOW_MSS:-0}
|
||||||
NOW_KA=$(cat /proc/sys/net/ipv4/tcp_keepalive_time 2>/dev/null || echo "?")
|
NOW_KA=$(cat /proc/sys/net/ipv4/tcp_keepalive_time 2>/dev/null || echo "?")
|
||||||
check "lanremote-relay 状态没变" "$NOW_RELAY" "$LIVE_RELAY_ACTIVE"
|
echo " 现在: relay=$NOW_RELAY tunnel=$NOW_TUNNEL h2=$NOW_TUNNEL2 MTU=$NOW_MTU MSS=$NOW_MSS KA=$NOW_KA"
|
||||||
check "lanremote-tunnel 状态没变" "$NOW_TUNNEL" "$LIVE_TUNNEL_ACTIVE"
|
check "lanremote-relay 状态没变" "$NOW_RELAY" "$LIVE_RELAY_ACTIVE"
|
||||||
check "wlan0 MTU 没变" "$NOW_MTU" "$LIVE_MTU"
|
check "lanremote-tunnel 状态没变" "$NOW_TUNNEL" "$LIVE_TUNNEL_ACTIVE"
|
||||||
check "MSS 规则数没变" "$NOW_MSS" "$LIVE_MSS"
|
check "lanremote-tunnel-h2 状态没变" "$NOW_TUNNEL2" "$LIVE_TUNNEL2_ACTIVE"
|
||||||
check "keepalive 没变" "$NOW_KA" "$LIVE_KEEPALIVE"
|
check "wlan0 MTU 没变" "$NOW_MTU" "$LIVE_MTU"
|
||||||
|
check "MSS 规则数没变" "$NOW_MSS" "$LIVE_MSS"
|
||||||
|
check "keepalive 没变" "$NOW_KA" "$LIVE_KEEPALIVE"
|
||||||
|
|
||||||
# ────────────────────────────────────────────────────────────
|
# ────────────────────────────────────────────────────────────
|
||||||
echo
|
echo
|
||||||
|
|||||||
@@ -572,6 +572,37 @@ check "非法协议退出码为 2" "$?" "2"
|
|||||||
bash "$DEPLOY" --prefix "$SANDBOX" --protocol both >/dev/null 2>&1
|
bash "$DEPLOY" --prefix "$SANDBOX" --protocol both >/dev/null 2>&1
|
||||||
check "both 是合法值" "$?" "0"
|
check "both 是合法值" "$?" "0"
|
||||||
|
|
||||||
|
echo
|
||||||
|
echo "── 7g. --port 换端口时 config.yml 必须跟着改 ──"
|
||||||
|
# 只改 unit 里的 RELAY_PORT、不改 config.yml 的话,
|
||||||
|
# 隧道会回源到老端口(没人听),现象是"隧道连上了但一访问就 502"。
|
||||||
|
if grep -q '127.0.0.1:8080' "$CFD/config.yml" 2>/dev/null; then
|
||||||
|
ok "换端口前 config.yml 是 8080"
|
||||||
|
else
|
||||||
|
bad "换端口前的基准不对"
|
||||||
|
fi
|
||||||
|
: > "$STUB_LOG"
|
||||||
|
printf 'lanremote-relay\n' > "$STUB_LOG.state"
|
||||||
|
bash "$DEPLOY" --prefix "$SANDBOX" --port 9090 > "$TMP/run7g.log" 2>&1
|
||||||
|
check "--port 9090 退出码为 0" "$?" "0"
|
||||||
|
if grep -q '127.0.0.1:9090' "$CFD/config.yml" 2>/dev/null; then
|
||||||
|
ok "config.yml 的回源端口跟到了 9090"
|
||||||
|
else
|
||||||
|
bad "config.yml 没跟着换端口(隧道会回源到错端口): $(grep -m1 'service:' "$CFD/config.yml")"
|
||||||
|
fi
|
||||||
|
if grep -q 'RELAY_PORT=9090' "$UNIT/lanremote-relay.service" 2>/dev/null; then
|
||||||
|
ok "relay unit 的端口也换成了 9090"
|
||||||
|
else
|
||||||
|
bad "relay unit 端口没换"
|
||||||
|
fi
|
||||||
|
# 换回 8080,后面的断言还要用
|
||||||
|
bash "$DEPLOY" --prefix "$SANDBOX" --port 8080 >/dev/null 2>&1
|
||||||
|
if grep -q '127.0.0.1:8080' "$CFD/config.yml" 2>/dev/null; then
|
||||||
|
ok "换回 8080 也跟上了"
|
||||||
|
else
|
||||||
|
bad "换回 8080 没跟上"
|
||||||
|
fi
|
||||||
|
|
||||||
echo
|
echo
|
||||||
echo "── 7b. 再跑一次(不给 --hostname),config.yml 不该被改 ──"
|
echo "── 7b. 再跑一次(不给 --hostname),config.yml 不该被改 ──"
|
||||||
H3=$(md5sum "$CFD/config.yml" | awk '{print $1}')
|
H3=$(md5sum "$CFD/config.yml" | awk '{print $1}')
|
||||||
|
|||||||
Binary file not shown.
|
Before Width: | Height: | Size: 1.4 MiB After Width: | Height: | Size: 1.4 MiB |
+16
-5
@@ -49,11 +49,22 @@ def main() -> int:
|
|||||||
check("OUTPUT 链上夹", "OUTPUT" in text)
|
check("OUTPUT 链上夹", "OUTPUT" in text)
|
||||||
check("POSTROUTING 链上夹", "POSTROUTING" in text)
|
check("POSTROUTING 链上夹", "POSTROUTING" in text)
|
||||||
|
|
||||||
# 关键:明确写了不要改接口 MTU,并且确实把接口 MTU 设回 1500
|
# ⚠ 这里原来断言的是"把接口 MTU 设回 1500",
|
||||||
check("不把接口 MTU 调小(写回了 1500)",
|
# 依据是更早的一次实测(接口 MTU 降到 1400 会掉到 50%)。
|
||||||
"mtu 1500" in text, "接口 MTU 降到 1400 实测会掉到 50%")
|
#
|
||||||
check("注释里说明了为什么不动接口 MTU",
|
# 那个结论后来被推翻了,原因是我们当时漏了一件事:
|
||||||
"不要改接口 MTU" in text or "反而" in text)
|
# **MSS 钳制只管 TCP,而 QUIC 走 UDP 完全不受保护。**
|
||||||
|
# 路径 MTU 实测 1472(1500 的包不通),QUIC 默认发 ~1452 的包
|
||||||
|
# 会被中间设备静默丢掉,而 UDP 丢了不回 ICMP,只能等超时。
|
||||||
|
# 把接口 MTU 压到 1400 之后,QUIC 建齐 10 条连接从 28 秒缩到 12 秒。
|
||||||
|
#
|
||||||
|
# 所以现在**故意**设 1400。这个断言跟着改,
|
||||||
|
# 否则它会永久假失败,还会诱导后人把真正的改进改回 1500。
|
||||||
|
check("把接口 MTU 压到 1400(QUIC 走 UDP,MSS 钳制管不到它)",
|
||||||
|
"mtu 1400" in text or "MTU_VALUE" in text,
|
||||||
|
"接口 MTU 要压到 1400,否则 QUIC 的大包会被静默丢弃")
|
||||||
|
check("注释里说明了为什么改接口 MTU(QUIC 不受 MSS 保护)",
|
||||||
|
"QUIC" in text or "UDP" in text or "MSS 钳制" in text)
|
||||||
|
|
||||||
# 清理旧规则,避免重启后越积越多
|
# 清理旧规则,避免重启后越积越多
|
||||||
check("会先清掉旧 MSS 规则", "-D" in text and "while" in text)
|
check("会先清掉旧 MSS 规则", "-D" in text and "while" in text)
|
||||||
|
|||||||
@@ -162,7 +162,7 @@
|
|||||||
========================================================
|
========================================================
|
||||||
|
|
||||||
软件名称:ykxmz
|
软件名称:ykxmz
|
||||||
版本:1.7.1
|
版本:1.8.2
|
||||||
作者:小麦子
|
作者:小麦子
|
||||||
|
|
||||||
请你**在安装之前**花三分钟读完这一页。里面有几条很要紧的
|
请你**在安装之前**花三分钟读完这一页。里面有几条很要紧的
|
||||||
@@ -186,6 +186,10 @@ ykxmz 是一套自己搭建的远程管理工具,由三部分组成:
|
|||||||
**关键点:所有数据都走你自己搭的那台服务器,
|
**关键点:所有数据都走你自己搭的那台服务器,
|
||||||
作者碰不到你的任何内容。** 详见《许可协议》第五条。
|
作者碰不到你的任何内容。** 详见《许可协议》第五条。
|
||||||
|
|
||||||
|
**再强调一次:软件里不带任何中转地址,作者也不对外提供中转服务。**
|
||||||
|
只在同一个 WiFi 下用的话,压根不需要中转站,装完就能连;
|
||||||
|
要跨网络就必须自己部署一台(看下面第四节的第 1 步)。
|
||||||
|
|
||||||
|
|
||||||
--------------------------------------------------------
|
--------------------------------------------------------
|
||||||
二、装机前对照检查
|
二、装机前对照检查
|
||||||
@@ -195,7 +199,7 @@ ykxmz 是一套自己搭建的远程管理工具,由三部分组成:
|
|||||||
|
|
||||||
[ ] 这台电脑是**你自己的**,或者设备主人明确同意你远程管理
|
[ ] 这台电脑是**你自己的**,或者设备主人明确同意你远程管理
|
||||||
[ ] 电脑是 Windows 10 / 11(64 位)
|
[ ] 电脑是 Windows 10 / 11(64 位)
|
||||||
[ ] 手表是安卓 9.0(API 28)或更高版本
|
[ ] 手表是安卓 7.0(API 24)或更高版本
|
||||||
[ ] 服务器端那台机器是 Linux(Debian 12 实测通过),
|
[ ] 服务器端那台机器是 Linux(Debian 12 实测通过),
|
||||||
能上外网,内存 512MB 够用
|
能上外网,内存 512MB 够用
|
||||||
[ ] 你有一个 Cloudflare 账号和一个域名(跨网络才需要)
|
[ ] 你有一个 Cloudflare 账号和一个域名(跨网络才需要)
|
||||||
@@ -243,19 +247,27 @@ ykxmz 是一套自己搭建的远程管理工具,由三部分组成:
|
|||||||
|
|
||||||
按这个顺序来,别跳:
|
按这个顺序来,别跳:
|
||||||
|
|
||||||
第 1 步 架服务器端(只做一次)
|
第 1 步 架服务器端(只做一次,**跨网络才需要**)
|
||||||
把 2-server 整个目录拷到随身 WiFi 上,执行:
|
如果只在同一个 WiFi 下用(手表和电脑连同一个路由器),
|
||||||
bash install.sh
|
这一步可以跳过。
|
||||||
它会装好中转服务 + Cloudflare 隧道,并打印一个
|
要跨网络的话,把 2-server 整个目录拷到那台 Linux 小机器上:
|
||||||
公网地址。
|
bash deploy.sh
|
||||||
|
它会把中转服务、网络调优、Cloudflare 隧道一次装好,
|
||||||
|
最后打印一个**属于你自己的公网地址**。记住它。
|
||||||
|
|
||||||
第 2 步 装被控端(每台要管理的电脑做一次)
|
第 2 步 装被控端(每台要管理的电脑做一次)
|
||||||
双击 ykxmz.exe -> 输 6 位配对码 -> 勾上开机自启和
|
双击安装包 -> 输 6 位配对码 -> 勾上开机自启和
|
||||||
放行防火墙 -> 确定。会弹一次管理员确认。
|
放行防火墙 -> 确定。会弹一次管理员确认。
|
||||||
|
|
||||||
第 3 步 装控制端
|
第 3 步 装控制端
|
||||||
把 3-watch 里的 APK 装到手表上。装完打开就能用,
|
把 3-watch 里的 APK 装到手表上。
|
||||||
地址已经内置好了。
|
|
||||||
|
第 4 步 跨网络的话,把中转地址填上
|
||||||
|
**注意:软件里没有内置任何中转地址。**
|
||||||
|
同一个 WiFi 下用不用填;跨网络的话必须填你自己第 1 步
|
||||||
|
装出来的那个地址:
|
||||||
|
电脑: ykxmz.exe --relay https://你的域名
|
||||||
|
手表: 首页点「中转设置」,填同一个地址
|
||||||
|
|
||||||
|
|
||||||
--------------------------------------------------------
|
--------------------------------------------------------
|
||||||
@@ -311,7 +323,7 @@ ykxmz 是一套自己搭建的远程管理工具,由三部分组成:
|
|||||||
|
|
||||||
--------------------------------------------------------
|
--------------------------------------------------------
|
||||||
作者:小麦子
|
作者:小麦子
|
||||||
软件:ykxmz 1.7.1
|
软件:ykxmz 1.8.2
|
||||||
继续安装,即表示你已阅读并同意《许可协议》。
|
继续安装,即表示你已阅读并同意《许可协议》。
|
||||||
--------------------------------------------------------
|
--------------------------------------------------------
|
||||||
|
|
||||||
@@ -322,7 +334,7 @@ ykxmz 是一套自己搭建的远程管理工具,由三部分组成:
|
|||||||
========================================================
|
========================================================
|
||||||
|
|
||||||
软件名称:ykxmz
|
软件名称:ykxmz
|
||||||
版本:1.7.1
|
版本:1.8.2
|
||||||
作者:小麦子
|
作者:小麦子
|
||||||
|
|
||||||
装好之后看这一页:怎么确认它在跑、怎么改设置、
|
装好之后看这一页:怎么确认它在跑、怎么改设置、
|
||||||
@@ -516,9 +528,18 @@ ykxmz 是一套自己搭建的远程管理工具,由三部分组成:
|
|||||||
八、版本记录
|
八、版本记录
|
||||||
--------------------------------------------------------
|
--------------------------------------------------------
|
||||||
|
|
||||||
|
1.8.2
|
||||||
|
* 下载改走 Cloudflare 边缘缓存 —— 安装包和 APK 快了几十倍
|
||||||
|
* 跨网络更稳:隧道**两种协议同时跑**(QUIC + HTTP/2,
|
||||||
|
合计 10 条连接),一种协议犯病另一种还在服务
|
||||||
|
* 修网卡 MTU 和 QUIC 不匹配(QUIC 走 UDP,之前不受 MSS 钳制保护),
|
||||||
|
隧道建连明显加快
|
||||||
|
* 修偶发"已断开"误报:连续失败 3 次才判离线
|
||||||
|
* **中转地址默认为空** —— 需要跨网络时自己填
|
||||||
|
|
||||||
1.7.1
|
1.7.1
|
||||||
* 跨网络支持:Cloudflare 具名隧道,固定域名
|
* 跨网络支持:Cloudflare 具名隧道,固定域名
|
||||||
* 中转服务器:单设备单配对码、管理页可删设备
|
* 中转服务器:单设备单配对码
|
||||||
* 手表端:自动判断局域网/中转并无缝切换
|
* 手表端:自动判断局域网/中转并无缝切换
|
||||||
* 被控端:所有开关和画面功能支持回退/撤销
|
* 被控端:所有开关和画面功能支持回退/撤销
|
||||||
* 配对码被占用时弹通知提示
|
* 配对码被占用时弹通知提示
|
||||||
@@ -528,6 +549,6 @@ ykxmz 是一套自己搭建的远程管理工具,由三部分组成:
|
|||||||
|
|
||||||
--------------------------------------------------------
|
--------------------------------------------------------
|
||||||
作者:小麦子
|
作者:小麦子
|
||||||
软件:ykxmz 1.7.1
|
软件:ykxmz 1.8.2
|
||||||
许可条款见《许可协议》(LICENSE.txt)
|
许可条款见《许可协议》(LICENSE.txt)
|
||||||
--------------------------------------------------------
|
--------------------------------------------------------
|
||||||
|
|||||||
+21
-3
@@ -675,9 +675,15 @@ else
|
|||||||
|
|
||||||
# 域名:命令行 > 已有 config.yml > 猜不出来就报错
|
# 域名:命令行 > 已有 config.yml > 猜不出来就报错
|
||||||
CUR_HOST=""
|
CUR_HOST=""
|
||||||
|
CUR_PORT=""
|
||||||
if [ -f "$CF_DIR/config.yml" ]; then
|
if [ -f "$CF_DIR/config.yml" ]; then
|
||||||
CUR_HOST=$(grep -m1 '^ *- hostname:' "$CF_DIR/config.yml" 2>/dev/null \
|
CUR_HOST=$(grep -m1 '^ *- hostname:' "$CF_DIR/config.yml" 2>/dev/null \
|
||||||
| sed 's/.*hostname: *//' | tr -d '"'"'"' ')
|
| sed 's/.*hostname: *//' | tr -d '"'"'"' ')
|
||||||
|
# 已有配置里的回源端口 —— 单独用 --port 换端口时,
|
||||||
|
# config.yml 还指着老端口的话隧道就回源到没人听的端口,
|
||||||
|
# 现象是"隧道连上了但一访问就 502",很难查。
|
||||||
|
CUR_PORT=$(grep -m1 'service: *http://127\.0\.0\.1:' "$CF_DIR/config.yml" 2>/dev/null \
|
||||||
|
| sed 's|.*127\.0\.0\.1:||' | tr -dc '0-9')
|
||||||
fi
|
fi
|
||||||
HOST="$HOSTNAME_ARG"
|
HOST="$HOSTNAME_ARG"
|
||||||
[ -z "$HOST" ] && HOST="$CUR_HOST"
|
[ -z "$HOST" ] && HOST="$CUR_HOST"
|
||||||
@@ -710,9 +716,21 @@ else
|
|||||||
say " 中转已经装好并启动了 —— **局域网内现在就能用**。"
|
say " 中转已经装好并启动了 —— **局域网内现在就能用**。"
|
||||||
say " 只是跨网络(走公网)还差这一步域名。"
|
say " 只是跨网络(走公网)还差这一步域名。"
|
||||||
else
|
else
|
||||||
# config.yml 只在「不存在」或「用户明确给了 --hostname」时才重写,
|
# config.yml 的重写条件,三种情况:
|
||||||
# 免得把别人手工调过的配置冲掉。
|
# 1. 本来就没有 —— 得生成一份
|
||||||
if [ ! -f "$CF_DIR/config.yml" ] || [ -n "$HOSTNAME_ARG" ]; then
|
# 2. 用户明确给了 --hostname —— 要按新域名改
|
||||||
|
# 3. 已有配置里的回源端口和当前 $PORT 不一致
|
||||||
|
# (单独跑 --port 9090 时,若不改这一行,
|
||||||
|
# 隧道还是回源到 8080,现象是"隧道通了但一访问就 502")
|
||||||
|
# 其他情况一律沿用,免得把别人手工调过的配置冲掉。
|
||||||
|
NEED_WRITE=0
|
||||||
|
[ ! -f "$CF_DIR/config.yml" ] && NEED_WRITE=1
|
||||||
|
[ -n "$HOSTNAME_ARG" ] && NEED_WRITE=1
|
||||||
|
if [ -n "$CUR_PORT" ] && [ "$CUR_PORT" != "$PORT" ]; then
|
||||||
|
NEED_WRITE=1
|
||||||
|
say " 已有 config.yml 指向端口 $CUR_PORT,当前是 $PORT —— 会一并更新"
|
||||||
|
fi
|
||||||
|
if [ "$NEED_WRITE" = "1" ]; then
|
||||||
cat > "$CF_DIR/config.yml" <<EOF
|
cat > "$CF_DIR/config.yml" <<EOF
|
||||||
# ykxmz 中转 · Cloudflare 具名隧道配置
|
# ykxmz 中转 · Cloudflare 具名隧道配置
|
||||||
# 由 deploy.sh 生成。改完记得 systemctl restart lanremote-tunnel
|
# 由 deploy.sh 生成。改完记得 systemctl restart lanremote-tunnel
|
||||||
|
|||||||
Reference in New Issue
Block a user