ykxmz 1.5.0:修复手表端 TLS 证书校验 + MTU 修复网络稳定性

被控端
- 修复 MTU 问题:夹 MSS + 路径 MTU 探测(公网可用率 48% -> 100%)
- 复用 HTTP 连接(免掉每次新建 TLS 的 30% 握手失败)
- 每分钟回头找局域网,自动切回快 400 倍的路径
- 画面心跳帧:静止时省流量,客户端仍知道流是活的
- 锁屏时给出可操作的提示

手表端
- 内置 GTS Root R4 / GlobalSign Root CA,修 SSLHandshakeException
- 连接错误翻译成人话(证书/时间/解析/超时分别提示)
- 经中转连上后用服务器报的地址刷新已配对记录
- 新增局域网连接页面、服务器延迟检测

服务器端
- 支持 chunked 请求体(修每 16 秒一次的连接错乱与大面积 502)
- 网络调优脚本 net-tune.sh(开机自动应用)
- 管理页:批量删除、网络体检、下载区
- 隧道改 HTTP/2 + 双连接

文档
- 许可协议 / 安装前必读 / 安装后须知(作者:小麦子)
This commit is contained in:
xmz7891
2026-10-06 19:01:05 +08:00
commit b62ac865ea
3195 changed files with 203292 additions and 0 deletions
+125
View File
@@ -0,0 +1,125 @@
# -*- coding: utf-8 -*-
"""让手表的连接错误提示说人话(尤其是证书问题)。
现在:
describeNetworkError(IOException) 只认 ETIMEDOUT / ECONNREFUSED /
ENETUNREACH 三种,其它原样把英文类名吐出来 ——
用户看到 "SSLHandshakeException: Chain validation failed" 完全不知道
该干嘛。
改后:
先交给 TlsCompat.explain()(它认得证书/时间/解析/超时等常见情况),
再补上"确认被控端在跑""确认同一个 WiFi"这些本场景专属的提示。
参数从 IOException 放宽到 Throwable —— 中转那边的异常可能是包过的。
"""
from __future__ import annotations
import sys
from pathlib import Path
MAIN = Path(r"C:\Users\shu\Desktop\deepseekagent\LanRemote\android\src"
r"\com\lanremote\watch\MainActivity.java")
OLD = ''' private String describeNetworkError(IOException e, String host) {
String message = e.getMessage() == null ? e.getClass().getSimpleName() : e.getMessage();
if (message.contains("ETIMEDOUT") || message.contains("timed out")) {
return "连接超时,检查电脑防火墙或 IP 是否正确";
}
if (message.contains("ECONNREFUSED") || message.contains("refused")) {
return "电脑拒绝连接,确认被控端程序正在运行";
}
if (message.contains("ENETUNREACH") || message.contains("Network is unreachable")) {
return "网络不可达,确认手表和电脑在同一个 WiFi";
}
return message;
}'''
NEW = ''' /**
* 把连接异常翻译成用户能看懂的话。
*
* <p>手表上原本只会显示一长串英文类名(比如
* {@code SSLHandshakeException: Chain validation failed}),
* 用户完全不知道该怎么办。这里按常见情况给出可操作的提示。
*
* <p>证书类问题交给 {@link TlsCompat#explain} 判断 ——
* 它会区分"证书链不认识""手表时间不对""被劫持"几种情况。
*/
private String describeNetworkError(Throwable e, String host) {
String raw = e == null ? ""
: String.valueOf(e.getMessage() == null
? e.getClass().getSimpleName() : e.getMessage());
String lower = raw.toLowerCase();
// 证书 / 时间 / 解析 / 超时 等通用情况
String friendly = TlsCompat.explain(e);
boolean generic = friendly != null && !friendly.equals(raw)
&& friendly.length() > 0;
// TlsCompat 认不出来时会原样返回,那就继续往下走本场景的判断
boolean recognized = generic && (
friendly.contains("证书") || friendly.contains("时间")
|| friendly.contains("超时") || friendly.contains("解析")
|| friendly.contains("拒绝") || friendly.contains("联网")
|| friendly.contains("中断"));
if (recognized) {
return friendly;
}
if (lower.contains("etimedout") || lower.contains("timed out")
|| lower.contains("timeout")) {
return "连接超时(网络慢或被防火墙挡了)";
}
if (lower.contains("econnrefused") || lower.contains("refused")) {
return "电脑拒绝连接 —— 确认电脑上 ykxmz 正在运行";
}
if (lower.contains("enetunreach")
|| lower.contains("network is unreachable")) {
return "网络不可达 —— 确认手表和电脑在同一个 WiFi";
}
if (lower.contains("ehostunreach") || lower.contains("no route")) {
return "找不到电脑 —— 检查 IP,或先用「局域网连接」搜一下";
}
if (lower.contains("unable to resolve host")
|| lower.contains("unknownhost")) {
return "域名解析不了 —— 检查手表能不能上网";
}
// 中转那边的错误信息一般是中文的,直接透传
if (raw.length() > 120) {
return raw.substring(0, 120);
}
return raw;
}'''
def main() -> int:
text = MAIN.read_text(encoding="utf-8")
if "TlsCompat.explain" in text:
print(" 已经改过")
return 0
if OLD not in text:
print(" [失败] 锚点没找到")
return 1
text = text.replace(OLD, NEW, 1)
# 把 catch 放宽到 Exception,别漏掉包过的异常
old_catch = ''' } catch (final IOException e) {
error = describeNetworkError(e, host);
}'''
new_catch = ''' } catch (final Exception e) {
// 放宽到 Exception:中转那边的异常可能是包过的,
// 只 catch IOException 会漏掉(甚至闪退)。
error = describeNetworkError(e, host);
}'''
if old_catch in text:
text = text.replace(old_catch, new_catch, 1)
print(" catch 从 IOException 放宽到 Exception")
else:
print(" [提示] catch 锚点没找到(可能已经在别处)")
MAIN.write_text(text, encoding="utf-8", newline="\n")
print(" describeNetworkError 已接上 TlsCompat.explain")
return 0
if __name__ == "__main__":
sys.exit(main())