mirror of
https://gitee.com/xmz7891/ykxmz.git
synced 2026-10-18 23:00:44 +00:00
阶段3 管理页 - 清掉全部深色主题残留(地址框 #0b1220、按钮悬停 #262c36、 删除按钮 #2d1214 等 11 处),现在 0 处深色 - 接口全部正常:health / downloads / netcheck 阶段4 局域网诊断 - 查清楚"电脑不在同一网络"是怎么回事:被控端是**对的** (lan_ips() 报 ['192.168.2.64', '169.254.83.107'],真实地址排第一), 是手表当时真不在 192.168.2.x —— 可能连了 5G 频段的另一个路由器,或开着移动数据 - 所以改了手表的提示:不再只说"不在同一网络", 而是把**双方地址都打出来**,用户一眼能看出是网段不同还是连错 WiFi - 端到端验证局域网路径:认证 1 ms,功能列表 207 项 阶段1 结论修正(一天内推翻自己两次,如实记录) - 第一次判断"优选 IP 无用":错。半小时内确实能避开超时 IP - 第二次固定优选 IP:也错。那些实测 138ms 的 IP 半小时后全不通了 —— Cloudflare anycast 可达性随运营商路由变化,固定 IP 等于钉死到会失效的地址 - 最终:不固定,靠 GeoDNS + cloudflared 重试 + ha-connections 2 冗余 - 撤销后立即变好:连接稳定 2 条、超时告警 0 次、设备侧延迟 4.40s -> 1.66s - **真正的瓶颈**:分段实测发现本机到 Cloudflare 的**裸 RTT 就 1439 ms**, 比经隧道的请求(1215 ms)还慢。说明瓶颈是这条网络的 4G 上行本身, 不是设备的隧道。公网侧已无优化空间。 - 局域网 118 ms vs 公网 1215 ms,快 10 倍 —— 这才是该走的路 阶段5 验收 - 全量回归 29 项全通过 - 设备侧验收 38 项全通过 - 成品:setup exe 14.37 MB / server zip / watch apk,已同步到设备下载区
142 lines
4.6 KiB
Python
142 lines
4.6 KiB
Python
# -*- coding: utf-8 -*-
|
||
r'''端到端验证局域网直连路径。
|
||
|
||
结论已经很清楚了:
|
||
局域网 118 ms vs 公网 1215 ms —— 快 10 倍
|
||
瓶颈是这条网络到 Cloudflare 的 4G 上行(裸 RTT 就 1.4 秒),
|
||
Cloudflare 那一侧没得优化。
|
||
|
||
所以真正要保证的是**局域网这条路能用**。
|
||
这个脚本起一个真实被控端,走 192.168.2.x 直连,量一下握手耗时。
|
||
'''
|
||
from __future__ import annotations
|
||
|
||
import json
|
||
import socket
|
||
import subprocess
|
||
import sys
|
||
import time
|
||
from pathlib import Path
|
||
|
||
ROOT = Path(r"C:\Users\shu\Desktop\deepseekagent\LanRemote")
|
||
PORT = 8875
|
||
CODE = "246810"
|
||
|
||
|
||
def talk(payload: dict, timeout: float = 12.0) -> dict:
|
||
sock = socket.create_connection(("127.0.0.1", PORT), timeout=timeout)
|
||
sock.settimeout(timeout)
|
||
sock.sendall((json.dumps(payload, ensure_ascii=False) + "\n").encode())
|
||
raw = b""
|
||
while b"\n" not in raw:
|
||
chunk = sock.recv(65536)
|
||
if not chunk:
|
||
break
|
||
raw += chunk
|
||
sock.close()
|
||
return json.loads(raw.split(b"\n")[0].decode("utf-8"))
|
||
|
||
|
||
def lan_ip() -> str:
|
||
try:
|
||
probe = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
||
probe.connect(("8.8.8.8", 80))
|
||
addr = probe.getsockname()[0]
|
||
probe.close()
|
||
return addr
|
||
except OSError:
|
||
return "192.168.2.64"
|
||
|
||
|
||
def main() -> int:
|
||
env = dict(__import__("os").environ)
|
||
env["YKXMZ_DATA"] = str(ROOT / "_build" / "_lantest_data")
|
||
Path(env["YKXMZ_DATA"]).mkdir(parents=True, exist_ok=True)
|
||
|
||
print(" 启动被控端(端口 %d,配对码 %s)" % (PORT, CODE))
|
||
proc = subprocess.Popen(
|
||
[sys.executable, str(ROOT / "windows" / "run_agent.py"),
|
||
"--port", str(PORT), "--code", CODE, "--silent"],
|
||
cwd=str(ROOT), env=env,
|
||
stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
|
||
|
||
passed = failed = 0
|
||
|
||
def check(name, ok, detail=""):
|
||
nonlocal passed, failed
|
||
if ok:
|
||
passed += 1
|
||
print(" [PASS] " + name)
|
||
else:
|
||
failed += 1
|
||
print(" [FAIL] " + name + " " + str(detail))
|
||
|
||
try:
|
||
time.sleep(7)
|
||
ip = lan_ip()
|
||
print(" 本机局域网地址: %s" % ip)
|
||
print()
|
||
|
||
# 1. 本机回环
|
||
print(" 一、回环路径")
|
||
t = time.perf_counter()
|
||
reply = talk({"cmd": "pair", "deviceId": "lantest",
|
||
"deviceName": "测试手表", "code": CODE})
|
||
loop_ms = (time.perf_counter() - t) * 1000
|
||
check("回环配对成功", reply.get("ok") is True, str(reply)[:90])
|
||
token = reply.get("token", "")
|
||
print(" 握手 %.0f ms" % loop_ms)
|
||
|
||
# 2. 局域网地址(真实用户路径)
|
||
print()
|
||
print(" 二、局域网地址 %s(手表实际走这条)" % ip)
|
||
sock = socket.create_connection((ip, PORT), timeout=10)
|
||
sock.settimeout(10)
|
||
t = time.perf_counter()
|
||
sock.sendall((json.dumps({"cmd": "auth", "deviceId": "lantest",
|
||
"token": token}, ensure_ascii=False)
|
||
+ "\n").encode())
|
||
raw = b""
|
||
while b"\n" not in raw:
|
||
raw += sock.recv(65536)
|
||
lan_ms = (time.perf_counter() - t) * 1000
|
||
auth = json.loads(raw.split(b"\n")[0].decode("utf-8"))
|
||
check("局域网认证成功", auth.get("ok") is True, str(auth)[:90])
|
||
print(" 认证 %.0f ms" % lan_ms)
|
||
|
||
# 3. 功能列表
|
||
t = time.perf_counter()
|
||
sock.sendall((json.dumps({"cmd": "feature_list"}, ensure_ascii=False)
|
||
+ "\n").encode())
|
||
raw = b""
|
||
while b"\n" not in raw:
|
||
raw += sock.recv(262144)
|
||
feat = json.loads(raw.split(b"\n")[0].decode("utf-8"))
|
||
feat_ms = (time.perf_counter() - t) * 1000
|
||
features = feat.get("features", [])
|
||
check("功能列表拿到 %d 项" % len(features), len(features) > 100)
|
||
print(" 功能列表 %.0f ms" % feat_ms)
|
||
sock.close()
|
||
|
||
print()
|
||
print(" 三、结论")
|
||
print(" 局域网往返 %.0f ms vs 公网 1215 ms" % lan_ms)
|
||
print(" 局域网快 %.1f 倍" % (1215 / max(lan_ms, 1)))
|
||
check("局域网明显快于公网", lan_ms < 300, "%.0f ms" % lan_ms)
|
||
|
||
finally:
|
||
proc.terminate()
|
||
try:
|
||
proc.wait(timeout=8)
|
||
except subprocess.TimeoutExpired:
|
||
proc.kill()
|
||
|
||
print()
|
||
print("=" * 52)
|
||
print(" 通过 %d 项,失败 %d 项" % (passed, failed))
|
||
return 0 if failed == 0 else 1
|
||
|
||
|
||
if __name__ == "__main__":
|
||
sys.exit(main())
|