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
+205
View File
@@ -0,0 +1,205 @@
# -*- coding: utf-8 -*-
"""应用内网络自检(原来是一个独立的控制台脚本,现在做进界面里)。
和独立脚本最大的区别:
被控端自己就在监听 8765/8766,所以**不需要再去绑端口**,
直接读它自己的计数器就知道手表的包有没有到:
* 自动发现请求收到几个
* TCP 连接来过几次
这比再开一个进程抢端口靠谱得多,也正是"连不上"时最想知道的事。
"""
from __future__ import annotations
import os
import platform
import socket
import subprocess
import time
from .config import app_dir
from .discovery import DISCOVERY_PORT
from .firewall import check as firewall_check
_NO_WINDOW = getattr(subprocess, "CREATE_NO_WINDOW", 0)
def _run(cmd: list[str], timeout: int = 12) -> str:
try:
proc = subprocess.run(cmd, capture_output=True, timeout=timeout,
creationflags=_NO_WINDOW,
encoding="mbcs" if os.name == "nt" else "utf-8",
errors="replace")
return (proc.stdout or "") + (proc.stderr or "")
except Exception: # noqa: BLE001
return ""
def local_ips() -> list[tuple[str, str]]:
"""本机所有可用的局域网 IPv4。"""
out: list[tuple[str, str]] = []
try:
probe = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
probe.connect(("8.8.8.8", 80))
addr = probe.getsockname()[0]
probe.close()
if addr and not addr.startswith("127."):
out.append((addr, "默认路由"))
except OSError:
pass
try:
for info in socket.getaddrinfo(socket.gethostname(), None, socket.AF_INET):
addr = info[4][0]
if addr and not addr.startswith("127.") and addr not in [a for a, _ in out]:
out.append((addr, "主机名"))
except OSError:
pass
return out
def wifi_name() -> str:
text = _run(["netsh", "wlan", "show", "interfaces"])
for raw in text.splitlines():
line = raw.strip()
if line.startswith("SSID") and "BSSID" not in line:
return line.split(":", 1)[-1].strip()
return ""
def collect(server, store) -> dict:
"""把自检需要的东西一次性收集出来。"""
data: dict = {
"time": time.strftime("%Y-%m-%d %H:%M:%S"),
"os": f"{platform.system()} {platform.release()}",
"ips": local_ips(),
"wifi": wifi_name(),
"port": getattr(server, "port", 0),
"discovery_port": DISCOVERY_PORT,
"server_running": bool(getattr(server, "running", False)),
"probes": 0,
"selfcheck_requests": 0,
"tcp_connections": 0,
"connected": [],
"firewall": {},
"app_dir": str(app_dir()),
}
# 服务端状态(含自动发现计数、累计 TCP 连接数)
try:
status = server.status()
data["connected"] = status.get("connected", [])
data["pairing_code"] = status.get("pairing_code", "")
data["screen_sharing"] = status.get("screen_sharing", False)
data["tcp_connections"] = int(status.get("total_connections", 0) or 0)
info = status.get("discovery") or {}
data["probes"] = int(info.get("answered", 0) or 0)
data["selfcheck_requests"] = int(info.get("selfcheck_requests", 0) or 0)
data["discovery_running"] = bool(info.get("running"))
data["discovery_error"] = info.get("error", "")
except Exception as exc: # noqa: BLE001
data["discovery_running"] = False
data["discovery_error"] = str(exc)
# 防火墙
try:
data["firewall"] = firewall_check(data["port"] or 8765, DISCOVERY_PORT)
except Exception as exc: # noqa: BLE001
data["firewall"] = {"supported": False, "message": str(exc)}
return data
def verdict(data: dict) -> tuple[str, str]:
"""给出结论:(级别, 文字)。级别是 ok / warn / error。"""
fw = data.get("firewall") or {}
if not data.get("server_running"):
return "error", "被控端没有在运行 —— 先启动它,否则手表一定连不上。"
if not fw.get("supported"):
return "warn", "防火墙状态读不到(可能不是 Windows),无法判断。"
if fw.get("blocked_count"):
return "error", (f"有 {fw['blocked_count']} 条「阻止」规则压着,"
"手表能搜到但连不上。去「设置/修复」点一键修复。")
if not (fw.get("tcp") and fw.get("udp")):
return "error", "端口放行规则缺失,其他设备连不上。点「一键修复」。"
if not fw.get("app_rule"):
return "warn", ("现在能连上,但程序级放行规则不完整,"
"以后系统可能再生成阻止规则。建议修一次。")
probes = data.get("probes", 0)
conns = data.get("tcp_connections", 0)
if probes == 0 and conns == 0:
return "warn", ("防火墙没问题,但**一个包都没收到**。"
"手表可能不在同一个 WiFi,或路由器开了 AP 隔离。")
return "ok", "一切正常,手表应该能连上。"
def render(data: dict) -> str:
"""把自检结果渲染成可复制的文本。"""
level, text = verdict(data)
lines: list[str] = []
lines.append("===== 电脑端自检 =====")
lines.append(f"时间: {data.get('time')}")
lines.append(f"系统: {data.get('os')}")
lines.append("")
lines.append("--- 本机网络 ---")
ips = data.get("ips") or []
if ips:
for addr, tag in ips:
lines.append(f" {addr} [{tag}]")
lines.append(f" >>> 手表上填这个 IP:{ips[0][0]}")
else:
lines.append(" 没读到 IP(网络没连上?)")
if data.get("wifi"):
lines.append(f" WiFi: {data['wifi']}")
lines.append("")
lines.append("--- 监听 ---")
lines.append(f" 控制端口 TCP {data.get('port')}: "
f"{'监听中' if data.get('server_running') else '未监听'}")
lines.append(f" 发现端口 UDP {data.get('discovery_port')}: "
f"{'监听中' if data.get('discovery_running') else '未监听'}")
if data.get("discovery_error"):
lines.append(f" 错误: {data['discovery_error']}")
lines.append("")
lines.append("--- 收到过多少(关键)---")
lines.append(f" 自动发现请求: {data.get('probes', 0)} 个")
lines.append(f" 自检请求: {data.get('selfcheck_requests', 0)} 个")
lines.append(f" TCP 连接: {data.get('tcp_connections', 0)} 次")
if data.get("probes", 0) == 0 and data.get("tcp_connections", 0) == 0:
lines.append(" !! 一直是 0 说明手表的包根本没到这台电脑")
else:
lines.append(" 有数字说明手表的包能到达这台电脑")
lines.append("")
lines.append("--- 防火墙 ---")
fw = data.get("firewall") or {}
lines.append(f" 端口放行 TCP: {'是' if fw.get('tcp') else '否'}")
lines.append(f" 端口放行 UDP: {'是' if fw.get('udp') else '否'}")
lines.append(f" 程序级放行: {'是' if fw.get('app_rule') else '否'} "
f"({os.path.basename(str(fw.get('app_rule_program') or '')) or '-'})")
lines.append(f" 阻止规则: {fw.get('blocked_count', 0)} 条(针对本程序)")
if fw.get("blocked_others"):
lines.append(f" 另外还有 {fw['blocked_others']} 条是针对别的程序的,不影响")
lines.append("")
lines.append("--- 已连接设备 ---")
connected = data.get("connected") or []
if connected:
for item in connected:
lines.append(f" {item.get('name', '?')} {item.get('addr', '')}")
else:
lines.append(" (没有设备连着)")
lines.append("")
lines.append("--- 结论 ---")
lines.append(f" [{level.upper()}] {text}")
lines.append("")
lines.append("===== 结束 =====")
return "\n".join(lines)