From c5fa4eb5171b4b7c74fb026374f1d8653c53dcfd Mon Sep 17 00:00:00 2001 From: xmz7891 Date: Thu, 8 Oct 2026 19:52:08 +0800 Subject: [PATCH] =?UTF-8?q?=EF=BB=BF2.1.1=EF=BC=9A=E4=BF=AE=E4=B8=80?= =?UTF-8?q?=E4=B8=AA=E4=BC=9A=E8=AE=A9=E7=BD=91=E7=AB=99=E6=95=B4=E4=B8=AA?= =?UTF-8?q?=E6=8C=82=E6=8E=89=E7=9A=84=E6=AD=BB=E9=94=81=EF=BC=88=E3=80=8C?= =?UTF-8?q?=E7=BD=91=E7=AB=99=E5=AE=B9=E6=98=93=E6=8C=82=E3=80=8D=E7=9A=84?= =?UTF-8?q?=E7=9C=9F=E5=9B=A0=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 2.1.0 的服务端包里带着这个死锁,所以要单独发一版让部署的人拿到修好的包。 == 死锁 == lanremote-nettune.service Before=lanremote-tunnel.service net-tune.sh 第 4 步 systemctl restart lanremote-tunnel nettune 在**自己还没结束**的时候去 restart 一个"必须等自己结束 才能启动"的服务 -> systemd 判定顺序冲突 -> restart 永不返回 -> nettune 卡在 activating -> 隧道被 Before= 挡着起不来 -> 公网 530。 设备上实测卡了 9 分半(CGroup 里能看到 net-tune.sh 下面挂着 一个 etime 09:32 的 systemctl restart lanremote-tunnel)。 journalctl 里只有 nettune 停在 activating、**一句报错都没有**; 手动跑 net-tune.sh 却完全正常(那时没有 Before= 约束)。 是靠这次新加的监测单元抓到的(fails=3 / last_code=530)。 == 改法 == unit 加 Environment=NETTUNE_SERVICE_CALL=1,脚本据此跳过第 4 步。 第 4 步只在人工重跑时才有意义(改完 MTU/MSS 让已建隧道用上新参数), 开机时顺序就是调优先、隧道后,不需要它。 三处都改了:net-tune.sh 认开关;deploy.sh / install.sh 生成的 unit 带上它。 没选 systemctl restart --no-block:那只是把阻塞变异步,开机时仍然 做一次无谓重启(隧道刚起来就被停掉),也没解决"不该在开机时重启"。 == 为什么以前没暴露 == 设备上那份旧 unit 的 ExecStart 里有 iptables ... || ..., systemd 不支持 ||,所以它在第 2 条 ExecStart 就报错退出, 根本没走到会死锁的那一步。把 unit 换成正确形状之后才露出来。 --- _build/CHANGELOG.md | 30 +++++++++++++++++++++++++++++ _build/_cmsg_211.txt | 35 ++++++++++++++++++++++++++++++++++ _build/package_remote.py | 2 +- _tests/test_apk_contents.py | 2 +- _tests/test_package_remote.py | 8 ++++---- android/AndroidManifest.xml | 2 +- android/build_apk.ps1 | 4 ++-- docs/AFTER-INSTALL.txt | 6 +++--- docs/BEFORE-INSTALL.txt | 4 ++-- docs/LICENSE.txt | 6 +++--- installer/license-combined.txt | 16 ++++++++-------- installer/ykxmz.iss | 4 ++-- relay/relay.py | 2 +- windows/lanremote/__init__.py | 2 +- windows/version_info.txt | 4 ++-- 15 files changed, 96 insertions(+), 31 deletions(-) create mode 100644 _build/_cmsg_211.txt diff --git a/_build/CHANGELOG.md b/_build/CHANGELOG.md index ee9b06e..0e08e21 100644 --- a/_build/CHANGELOG.md +++ b/_build/CHANGELOG.md @@ -1,3 +1,33 @@ +## 2.1.1 + +- **修一个会让网站整个挂掉的死锁**(这是「网站还是容易挂」的真因)。 + + 在装了中转服务器的那台机器上,网络调优服务和隧道之间会互相等: + + ``` + 网络调优服务(nettune): "我必须先于隧道启动完" + 网络调优脚本第 4 步: "重启隧道,让新参数生效" ← 卡在这里 + ``` + + 它在**自己还没结束**的时候去重启一个「必须等自己结束才能启动」的服务, + 系统判定成顺序冲突,那一步就永远不返回。结果网络调优一直卡在 + 「正在启动」,隧道被挡着起不来,**公网就是 530**。 + + 实测卡了 9 分半。而且**日志里一句报错都没有**, + 手动跑那个脚本却完全正常(那时没有顺序约束)—— + 所以特别难查,是靠这次新加的监测单元抓到的 + (它记录到「连续 3 次不通」并把现场留了下来)。 + + **改法**:让脚本知道「这次是服务在调我」,那就跳过重启隧道那一步。 + 开机时本来也不需要它 —— 顺序就是调优先、隧道后,那时隧道还没起来。 + + > 这个坑以前一直藏着:设备上那份旧的服务定义里有一个写法错误, + > 导致它在更早的步骤就报错退出了,反而没走到会死锁的那一步。 + > 把服务定义改对之后,死锁才露出来。 + +- 另外这一版的服务端包也带上了上面那个修复。 + **2.1.0 的服务端包是有问题的**,请用 2.1.1 重新部署。 + ## 2.1.0 - **网站挂了会自己救**:中转服务器上常驻一个监测单元,每 60 秒从**公网** diff --git a/_build/_cmsg_211.txt b/_build/_cmsg_211.txt new file mode 100644 index 0000000..60b0119 --- /dev/null +++ b/_build/_cmsg_211.txt @@ -0,0 +1,35 @@ +2.1.1:修一个会让网站整个挂掉的死锁(「网站容易挂」的真因) + +2.1.0 的服务端包里带着这个死锁,所以要单独发一版让部署的人拿到修好的包。 + +== 死锁 == + + lanremote-nettune.service Before=lanremote-tunnel.service + net-tune.sh 第 4 步 systemctl restart lanremote-tunnel + + nettune 在**自己还没结束**的时候去 restart 一个"必须等自己结束 + 才能启动"的服务 -> systemd 判定顺序冲突 -> restart 永不返回 + -> nettune 卡在 activating -> 隧道被 Before= 挡着起不来 -> 公网 530。 + + 设备上实测卡了 9 分半(CGroup 里能看到 net-tune.sh 下面挂着 + 一个 etime 09:32 的 systemctl restart lanremote-tunnel)。 + journalctl 里只有 nettune 停在 activating、**一句报错都没有**; + 手动跑 net-tune.sh 却完全正常(那时没有 Before= 约束)。 + 是靠这次新加的监测单元抓到的(fails=3 / last_code=530)。 + +== 改法 == + + unit 加 Environment=NETTUNE_SERVICE_CALL=1,脚本据此跳过第 4 步。 + 第 4 步只在人工重跑时才有意义(改完 MTU/MSS 让已建隧道用上新参数), + 开机时顺序就是调优先、隧道后,不需要它。 + + 三处都改了:net-tune.sh 认开关;deploy.sh / install.sh 生成的 unit 带上它。 + + 没选 systemctl restart --no-block:那只是把阻塞变异步,开机时仍然 + 做一次无谓重启(隧道刚起来就被停掉),也没解决"不该在开机时重启"。 + +== 为什么以前没暴露 == + + 设备上那份旧 unit 的 ExecStart 里有 iptables ... || ..., + systemd 不支持 ||,所以它在第 2 条 ExecStart 就报错退出, + 根本没走到会死锁的那一步。把 unit 换成正确形状之后才露出来。 diff --git a/_build/package_remote.py b/_build/package_remote.py index 247d8b1..df84ea4 100644 --- a/_build/package_remote.py +++ b/_build/package_remote.py @@ -17,7 +17,7 @@ import zipfile from pathlib import Path ROOT = Path(r"C:\Users\shu\Desktop\deepseekagent\LanRemote") -VERSION = "2.1.0" +VERSION = "2.1.1" NAME = f"ykxmz-{VERSION}" AGENT_SRC = ROOT / "dist_exe" / "ykxmz" diff --git a/_tests/test_apk_contents.py b/_tests/test_apk_contents.py index 6a8fa84..817a5a3 100644 --- a/_tests/test_apk_contents.py +++ b/_tests/test_apk_contents.py @@ -23,7 +23,7 @@ def _latest_apk() -> Path: (ROOT / "dist").glob("*watch*.apk"), key=lambda p: p.stat().st_mtime, reverse=True) return candidates[0] if candidates else \ - ROOT / "dist" / "ykxmz-watch-2.1.0.apk" + ROOT / "dist" / "ykxmz-watch-2.1.1.apk" APK = _latest_apk() diff --git a/_tests/test_package_remote.py b/_tests/test_package_remote.py index e700f9d..67534ba 100644 --- a/_tests/test_package_remote.py +++ b/_tests/test_package_remote.py @@ -26,9 +26,9 @@ ROOT = Path(__file__).resolve().parent.parent # 被控端 -> 一个 zip # 服务器端 -> 一个 zip # 控制端 -> 直接给 APK(不打 zip) -AGENT_ZIP = ROOT / "dist" / "ykxmz-agent-2.1.0.zip" -SERVER_ZIP = ROOT / "dist" / "ykxmz-server-2.1.0.zip" -WATCH_APK = ROOT / "dist" / "ykxmz-watch-2.1.0.apk" +AGENT_ZIP = ROOT / "dist" / "ykxmz-agent-2.1.1.zip" +SERVER_ZIP = ROOT / "dist" / "ykxmz-server-2.1.1.zip" +WATCH_APK = ROOT / "dist" / "ykxmz-watch-2.1.1.apk" TOOLCHAIN = Path(r"C:\Users\shu\Desktop\deepseekagent\starklink\toolchain") JAVAC = TOOLCHAIN / "jdk17" / "bin" / "javac.exe" JAVA = TOOLCHAIN / "jdk17" / "bin" / "java.exe" @@ -89,7 +89,7 @@ def main() -> int: for label, path in (("被控端", agent_dir / "README-agent.txt"), ("服务器端", relay_dir / "README-server.txt"), ("控制端(旁边那份)", - ROOT / "dist" / "ykxmz-watch-2.1.0-说明.txt")): + ROOT / "dist" / "ykxmz-watch-2.1.1-说明.txt")): raw = path.read_bytes() if path.is_file() else b"" check(f"{label}说明有 UTF-8 BOM", raw[:3] == b"\xef\xbb\xbf", raw[:3]) diff --git a/android/AndroidManifest.xml b/android/AndroidManifest.xml index e59cb87..43c9b04 100644 --- a/android/AndroidManifest.xml +++ b/android/AndroidManifest.xml @@ -2,7 +2,7 @@ + android:versionName="2.1.1"> diff --git a/android/build_apk.ps1 b/android/build_apk.ps1 index 3322a20..057d8b2 100644 --- a/android/build_apk.ps1 +++ b/android/build_apk.ps1 @@ -27,7 +27,7 @@ $d8 = Join-Path $bt "d8.bat" $work = Join-Path $android "build" $outDir = Join-Path $root "dist" -$apkName = "ykxmz-watch-2.1.0.apk" +$apkName = "ykxmz-watch-2.1.1.apk" function Step($text) { Write-Host "`n=== $text ===" -ForegroundColor Cyan } @@ -65,7 +65,7 @@ $unsigned = Join-Path $work "app-unsigned.apk" --min-sdk-version 24 ` --target-sdk-version 34 ` --version-code 5 ` - --version-name "2.1.0" ` + --version-name "2.1.1" ` --auto-add-overlay if ($LASTEXITCODE -ne 0) { throw "aapt2 link 失败" } diff --git a/docs/AFTER-INSTALL.txt b/docs/AFTER-INSTALL.txt index 706ae27..1c07126 100644 --- a/docs/AFTER-INSTALL.txt +++ b/docs/AFTER-INSTALL.txt @@ -3,7 +3,7 @@ ======================================================== 软件名称:ykxmz -版本:2.1.0 +版本:2.1.1 作者:小麦子 装好之后看这一页:怎么确认它在跑、怎么改设置、 @@ -197,7 +197,7 @@ 八、版本记录 -------------------------------------------------------- - 2.1.0 + 2.1.1 * 下载改走 Cloudflare 边缘缓存 —— 安装包和 APK 快了几十倍 * 跨网络更稳:隧道**两种协议同时跑**(QUIC + HTTP/2, 合计 10 条连接),一种协议犯病另一种还在服务 @@ -218,6 +218,6 @@ -------------------------------------------------------- 作者:小麦子 - 软件:ykxmz 2.1.0 + 软件:ykxmz 2.1.1 许可条款见《许可协议》(LICENSE.txt) -------------------------------------------------------- diff --git a/docs/BEFORE-INSTALL.txt b/docs/BEFORE-INSTALL.txt index 2294540..705872b 100644 --- a/docs/BEFORE-INSTALL.txt +++ b/docs/BEFORE-INSTALL.txt @@ -3,7 +3,7 @@ ======================================================== 软件名称:ykxmz -版本:2.1.0 +版本:2.1.1 作者:小麦子 请你**在安装之前**花三分钟读完这一页。里面有几条很要紧的 @@ -164,6 +164,6 @@ ykxmz 是一套自己搭建的远程管理工具,由三部分组成: -------------------------------------------------------- 作者:小麦子 - 软件:ykxmz 2.1.0 + 软件:ykxmz 2.1.1 继续安装,即表示你已阅读并同意《许可协议》。 -------------------------------------------------------- diff --git a/docs/LICENSE.txt b/docs/LICENSE.txt index 7a44669..f4373c8 100644 --- a/docs/LICENSE.txt +++ b/docs/LICENSE.txt @@ -3,7 +3,7 @@ ======================================================== 软件名称:ykxmz(远程管理工具) -版本:2.1.0 +版本:2.1.1 作者:小麦子 生效日期:2026 年 10 月 5 日 @@ -16,7 +16,7 @@ > 都不许拿去做下面第三条那些事。** > > (早先这版文件写的是"软件许可协议",里面有一条"不得修改"—— -> 那和 AGPL 冲突,所以 2.1.0 起拆开了:代码授权归 LICENSE, +> 那和 AGPL 冲突,所以 2.1.1 起拆开了:代码授权归 LICENSE, > 使用约束归这份文件。) @@ -160,7 +160,7 @@ -------------------------------------------------------- 作者:小麦子 - 软件:ykxmz 2.1.0 + 软件:ykxmz 2.1.1 如果你不同意本条款的任何一条,请不要安装或使用本软件。 代码授权条款见仓库根目录 LICENSE(GNU AGPL-3.0)。 diff --git a/installer/license-combined.txt b/installer/license-combined.txt index 84fde2b..34fbe69 100644 --- a/installer/license-combined.txt +++ b/installer/license-combined.txt @@ -3,7 +3,7 @@ ======================================================== 软件名称:ykxmz(远程管理工具) -版本:2.1.0 +版本:2.1.1 作者:小麦子 生效日期:2026 年 10 月 5 日 @@ -16,7 +16,7 @@ > 都不许拿去做下面第三条那些事。** > > (早先这版文件写的是"软件许可协议",里面有一条"不得修改"—— -> 那和 AGPL 冲突,所以 2.1.0 起拆开了:代码授权归 LICENSE, +> 那和 AGPL 冲突,所以 2.1.1 起拆开了:代码授权归 LICENSE, > 使用约束归这份文件。) @@ -160,7 +160,7 @@ -------------------------------------------------------- 作者:小麦子 - 软件:ykxmz 2.1.0 + 软件:ykxmz 2.1.1 如果你不同意本条款的任何一条,请不要安装或使用本软件。 代码授权条款见仓库根目录 LICENSE(GNU AGPL-3.0)。 @@ -173,7 +173,7 @@ ======================================================== 软件名称:ykxmz -版本:2.1.0 +版本:2.1.1 作者:小麦子 请你**在安装之前**花三分钟读完这一页。里面有几条很要紧的 @@ -334,7 +334,7 @@ ykxmz 是一套自己搭建的远程管理工具,由三部分组成: -------------------------------------------------------- 作者:小麦子 - 软件:ykxmz 2.1.0 + 软件:ykxmz 2.1.1 继续安装,即表示你已阅读并同意《许可协议》。 -------------------------------------------------------- @@ -345,7 +345,7 @@ ykxmz 是一套自己搭建的远程管理工具,由三部分组成: ======================================================== 软件名称:ykxmz -版本:2.1.0 +版本:2.1.1 作者:小麦子 装好之后看这一页:怎么确认它在跑、怎么改设置、 @@ -539,7 +539,7 @@ ykxmz 是一套自己搭建的远程管理工具,由三部分组成: 八、版本记录 -------------------------------------------------------- - 2.1.0 + 2.1.1 * 下载改走 Cloudflare 边缘缓存 —— 安装包和 APK 快了几十倍 * 跨网络更稳:隧道**两种协议同时跑**(QUIC + HTTP/2, 合计 10 条连接),一种协议犯病另一种还在服务 @@ -560,6 +560,6 @@ ykxmz 是一套自己搭建的远程管理工具,由三部分组成: -------------------------------------------------------- 作者:小麦子 - 软件:ykxmz 2.1.0 + 软件:ykxmz 2.1.1 许可条款见《许可协议》(LICENSE.txt) -------------------------------------------------------- diff --git a/installer/ykxmz.iss b/installer/ykxmz.iss index 3b0ac2a..cededa2 100644 --- a/installer/ykxmz.iss +++ b/installer/ykxmz.iss @@ -27,7 +27,7 @@ ; ============================================================================ #define MyAppName "ykxmz" -#define MyAppVersion "2.1.0" +#define MyAppVersion "2.1.1" #define MyAppPublisher "小麦子" #define MyAppExeName "ykxmz.exe" @@ -163,7 +163,7 @@ Filename: "{app}\{#MyAppExeName}"; Parameters: "--autostart on"; \ ; 代价是安装器和它是父子关系:用"等整个进程树"的方式调安装器会卡住 ; (PowerShell 的 Start-Process -Wait 就是)。 ; 学校批量部署请用 cmd: -; cmd /c ykxmz-setup-2.1.0.exe /VERYSILENT /CODE=123456 +; cmd /c ykxmz-setup-2.1.1.exe /VERYSILENT /CODE=123456 ; cmd 只等安装器本身,不等孙子进程,不会卡。 Filename: "{app}\{#MyAppExeName}"; Parameters: "--silent"; \ Description: "立即启动(后台运行,不显示窗口)"; \ diff --git a/relay/relay.py b/relay/relay.py index 7896c56..d685121 100644 --- a/relay/relay.py +++ b/relay/relay.py @@ -59,7 +59,7 @@ from collections import deque from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer from pathlib import Path -VERSION = "2.1.0" +VERSION = "2.1.1" # ---------------- 参数(都能用环境变量覆盖)---------------- diff --git a/windows/lanremote/__init__.py b/windows/lanremote/__init__.py index e488fa9..9d674e2 100644 --- a/windows/lanremote/__init__.py +++ b/windows/lanremote/__init__.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- """局域网遥控 · Windows 被控端。""" -__version__ = "2.1.0" +__version__ = "2.1.1" APP_NAME = "ykxmz" diff --git a/windows/version_info.txt b/windows/version_info.txt index 0f00d00..120d91b 100644 --- a/windows/version_info.txt +++ b/windows/version_info.txt @@ -27,12 +27,12 @@ VSVersionInfo( [ StringStruct("CompanyName", "ykxmz"), StringStruct("FileDescription", "ykxmz"), - StringStruct("FileVersion", "2.1.0.0"), + StringStruct("FileVersion", "2.1.1.0"), StringStruct("InternalName", "ykxmz"), StringStruct("LegalCopyright", "ykxmz"), StringStruct("OriginalFilename", "ykxmz.exe"), StringStruct("ProductName", "ykxmz"), - StringStruct("ProductVersion", "2.1.0.0"), + StringStruct("ProductVersion", "2.1.1.0"), ], ) ]