Files
ykxmz/_build/package.py
T
xmz7891 b62ac865ea 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 + 双连接

文档
- 许可协议 / 安装前必读 / 安装后须知(作者:小麦子)
2026-10-06 19:01:05 +08:00

222 lines
7.8 KiB
Python
Raw 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.
# -*- coding: utf-8 -*-
"""统一打包:被控端 + 手表端(已内置诊断)+ 文档。
注意:遥控诊断原来是一个单独的 App,现在已合并进手表主程序
(主界面 ->「设备诊断」按钮),所以不再单独出 APK。
产物(都在 dist/):
ykxmz-Windows.zip 被控端(解压即用,内含工具箱)
LanRemote-Watch-1.3.0.apk 手表控制端(含设备诊断)
LanRemote-1.3.0-完整包.zip 以上全部 + 预览图 + 文档
被控端目录结构(解压后):
LanRemote-Agent/
├── (已移除) <- 双击这个,所有功能都在菜单里
├── ykxmz.exe
├── _internal/
├── xffhq.bat
├── wlzj.bat / .py
├── 使用说明.txt
└── 先看这个.txt
"""
from __future__ import annotations
import shutil
import sys
import zipfile
from pathlib import Path
VERSION = "1.4.0"
ROOT = Path(__file__).resolve().parent.parent
DIST = ROOT / "dist"
EXE_DIR = ROOT / "dist_exe" / "ykxmz"
TOOLS = ROOT / "tools"
PREVIEW = ROOT / "dist_preview"
README = ROOT / "README.md"
TEST_REPORT = DIST / "测试报告.txt"
APK = DIST / f"LanRemote-Watch-{VERSION}.apk"
AGENT_ZIP = DIST / "ykxmz-Windows.zip"
BUNDLE = DIST / f"LanRemote-{VERSION}-完整包.zip"
# 会被放进被控端目录的工具(工具箱必须排第一)
TOOL_FILES = (
"fxfhq.bat",
"wlzj.bat",
"xffhq.bat",
)
QUICKSTART = f"""========================================================
局域网遥控 · 被控端(Windows) 版本 {VERSION}
========================================================
*** 不需要装 Python ***
这个目录里的 ykxmz.exe 是编译好的独立程序,
拷到任何一台 Windows 电脑上双击就能跑。
【装完之后怎么用】
1) 双击 ykxmz.exe
2) 弹出一个小窗口,让你输入 6 位数字(配对码)
自己定一个记得住的,比如 789113
下面有两个勾:
[x] 设置开机自启(开机后自动在后台运行)
[x] 顺便放行防火墙(需要管理员确认一次)
3) 点「确定,开始使用」
→ 会弹一次 Windows 的管理员确认(UAC),点「是」
→ 黑色终端窗口一闪,它在一键修复防火墙
→ 窗口全部消失,程序转入后台静默运行
4) 手表上打开 App → 点「自动搜索电脑」→ 点搜到的电脑
→ 输入你设的 6 位数字
5) 以后开机就直接在后台跑,屏幕上什么都没有;
手表打开 App 会自动连上,数字都不用再输。
【目录里这几个文件】
ykxmz.exe 主程序。双击就是上面第 1 步。
wlzj.bat 网络自检。连不上时跑它,看手表的包到底有没有到电脑。
xffhq.bat 一键修复防火墙。右键 →「以管理员身份运行」。
fxfhq.bat 同上,是程序自动生成的放行脚本,也可以右键提权运行。
先看这个.txt / 使用说明.txt 就是本文。
三个 .bat 都不需要装 Python。
【连不上?按这个顺序来】
1) 确认被控端在跑
任务管理器里能看到 ykxmz.exe
没有的话:ykxmz.exe --setup
2) 右键 xffhq.bat →「以管理员身份运行」,点「是」
3) 还不行 → 双击 wlzj.bat(网络自检)
它会监听 90 秒,看手表的请求有没有到达这台电脑:
收到连接 -> 网络是通的,问题在电脑这边
一直没动静 -> 包没到电脑,多半路由器开了「AP 隔离」
4) 手表上:首页「连不上?点这里诊断」
【命令行参数】(一般用不到)
ykxmz.exe --setup 重新打开设置窗口
ykxmz.exe --silent 直接静默运行
ykxmz.exe --add-device 10 静默运行 + 开放 10 分钟配对
ykxmz.exe --autostart on|off 开关开机自启
ykxmz.exe --status 看当前状态
ykxmz.exe --netcheck 90 网络自检(同 wlzj.bat)
ykxmz.exe --fix-firewall 提权修复防火墙
ykxmz.exe --reset-devices 清空已配对设备
【关于安全】
配对码是你自己设的,只存在这台电脑的 data\\settings.json 里。
一台设备都没配对过时配对是开着的(否则你设完码会连不上自己);
第一台配对成功后自动关闭。
配错 10 次锁 5 分钟(按来源 IP 分别计,别人锁不住你)。
屏幕共享时右下角会出现一条红色小提示 ——
这是故意的:有人在看你的屏幕时,屏幕前面的人应该知道。
"""
def clean_runtime_state() -> None:
"""打包前清掉运行时产生的东西,保持交付干净。"""
for name in ("data", "received"):
target = EXE_DIR / name
if target.exists():
shutil.rmtree(target, ignore_errors=True)
print(f" 已清理 {target.relative_to(ROOT)}")
for stale in ("fxfhq.bat",):
path = EXE_DIR / stale
if path.exists():
path.unlink()
print(f" 已清理 {stale}")
def install_tools() -> list[str]:
installed = []
for name in TOOL_FILES:
source = TOOLS / name
if source.is_file():
shutil.copy2(source, EXE_DIR / name)
installed.append(name)
else:
print(f" [警告] 缺少工具: {name}")
return installed
def zip_dir(source: Path, target: Path, arc_prefix: str = "") -> int:
files = [p for p in source.rglob("*") if p.is_file()]
with zipfile.ZipFile(target, "w", zipfile.ZIP_DEFLATED, compresslevel=6) as zf:
for path in files:
rel = path.relative_to(source)
arc = str(Path(arc_prefix) / rel) if arc_prefix else str(rel)
zf.write(path, arc)
print(f" {target.name} ({target.stat().st_size / 1048576:.1f} MB, {len(files)} 个文件)")
return len(files)
def main() -> int:
missing = []
if not EXE_DIR.is_dir():
missing.append(f"被控端产物目录 {EXE_DIR}(先运行 windows\\build_exe.ps1)")
if not APK.is_file():
missing.append(f"{APK.name}(先运行 android\\build_apk.ps1)")
if missing:
print("缺少产物:")
for item in missing:
print(f" - {item}")
return 1
DIST.mkdir(parents=True, exist_ok=True)
print("清理测试残留:")
clean_runtime_state()
print("\n安装工具到被控端目录:")
installed = install_tools()
for name in installed:
print(f" + {name}")
(EXE_DIR / "使用说明.txt").write_text(QUICKSTART, encoding="utf-8")
(EXE_DIR / "先看这个.txt").write_text(QUICKSTART, encoding="utf-8")
print(" + 使用说明.txt / 先看这个.txt")
print("\n打包被控端:")
count = zip_dir(EXE_DIR, AGENT_ZIP, arc_prefix="ykxmz")
print("\n打包完整交付:")
with zipfile.ZipFile(BUNDLE, "w", zipfile.ZIP_DEFLATED, compresslevel=6) as zf:
zf.writestr("先看这个.txt", QUICKSTART)
zf.write(APK, f"1-手表控制端/{APK.name}")
zf.write(AGENT_ZIP, f"2-电脑被控端/{AGENT_ZIP.name}")
if PREVIEW.is_dir():
for shot in sorted(PREVIEW.glob("*.png")):
zf.write(shot, f"3-界面预览/{shot.name}")
if README.is_file():
zf.write(README, "使用说明.md")
if TEST_REPORT.is_file():
zf.write(TEST_REPORT, "测试报告.txt")
print(f" {BUNDLE.name} ({BUNDLE.stat().st_size / 1048576:.1f} MB)")
print("\n" + "=" * 62)
print(f"交付内容(版本 {VERSION}):")
for path in (APK, AGENT_ZIP, BUNDLE):
print(f" {path.stat().st_size / 1048576:7.2f} MB {path.name}")
print(f"\n被控端包内含 {count} 个文件,工具箱等 {len(installed)} 个工具已就位。")
print("遥控诊断已合并进手表主程序,不再单独出包。")
return 0
if __name__ == "__main__":
sys.exit(main())