# -*- coding: utf-8 -*- """任务 A:放行防火墙之前,配对码不加入服务器。 任务 B:性能提升。 ──────────────────────────────────────── A. 配对码门禁 ──────────────────────────────────────── 用户要求:"在放行防火墙之前配对码不会加入服务器" 现在的顺序: 检查码(只读) -> 存码 -> 开自启 -> 放行防火墙 -> run_silent(注册) 虽然注册在防火墙之后,但**防火墙失败也照样注册** —— 服务器上就挂着一个谁也连不上的配对码。 改成: 防火墙没放行成功 -> 不注册,告诉用户 ──────────────────────────────────────── B. 性能 ──────────────────────────────────────── 实测(本机 1920x1080): 抓屏 ImageGrab.grab() 33 ms <- 硬开销,决定了上限 缩放 + JPEG 编码 17 ms (BILINEAR, 960 宽) 合计 50 ms -> 约 20 帧/秒 问题: 1. screen_fps 默认只有 3 —— 白白浪费了 20 帧的能力 2. screen_quality 默认 55 —— 偏糊 3. **画面没变也照抓照编码照发** —— 手表看静态桌面时白烧 CPU 和流量 改动: 1. 默认帧率 3 -> 12 2. 默认质量 55 -> 72 3. 加"画面没变就跳过":用 32x18 缩略图做指纹(很便宜), 指纹一样就不编码、不发送,并把采样间隔逐级拉长(最多 4 倍), 画面一变立刻恢复满帧率。 """ from __future__ import annotations import sys from pathlib import Path ROOT = Path(r"C:\Users\shu\Desktop\deepseekagent\LanRemote") RUN = ROOT / "windows" / "run_agent.py" CONFIG = ROOT / "windows" / "lanremote" / "config.py" SCREEN = ROOT / "windows" / "lanremote" / "screen.py" # ================= A. 配对码门禁 ================= A_OLD = ''' # 黑终端一闪:修防火墙 if result["firewall"]: fix_firewall_with_flash(store) ''' A_NEW = ''' # 黑终端一闪:修防火墙 firewall_ok = True firewall_note = "" if result["firewall"]: firewall_ok, firewall_note = fix_firewall_with_flash(store) # 放行防火墙之前,配对码**不加入服务器**。 # # 为什么:注册(= 配对码挂到服务器上)如果发生在防火墙之前, # 那么防火墙没放行成功时,服务器上会留着一个谁也连不上的码, # 而且它会把码占住,用户重装都换不了。 # 所以这里卡一道:防火墙没成功就不注册。 if not firewall_ok: _tell_firewall_problem(firewall_note) return 3 ''' HELPER_ANCHOR = "def _tell_code_problem(message: str) -> None:" HELPER_NEW = '''def _tell_firewall_problem(detail: str) -> None: """防火墙没放行成功,说明为什么这次没生效。""" message = ( "防火墙没有放行成功,所以这次**没有**把配对码交给服务器。\\n\\n" f"原因:{detail or '未知'}\\n\\n" "该怎么办:\\n" " 1. 右键点 ykxmz.exe →「以管理员身份运行」,重新走一遍设置\\n" " 2. 或者手动放行:控制面板 → Windows Defender 防火墙 →\\n" " 允许应用通过防火墙 → 找到 ykxmz → 勾上「专用网络」\\n\\n" "放行之后再打开 ykxmz.exe 就行了。" ) try: import tkinter as tk from tkinter import messagebox root = tk.Tk() root.withdraw() root.attributes("-topmost", True) messagebox.showerror("还没生效:防火墙没放行", message) root.destroy() return except Exception: # noqa: BLE001 pass print("=" * 56) print("防火墙没放行,配对码未提交到服务器") print(message) print("=" * 56) ''' + HELPER_ANCHOR # ================= B1. 默认参数 ================= CFG_OLD = ''' "screen_quality": 55, # 镜像 JPEG 质量 "screen_fps": 3, # 默认帧率''' CFG_NEW = ''' # 镜像 JPEG 质量。 # 实测质量对编码耗时几乎没影响(都是 ~17ms),主要影响体积: # 55 -> 30KB/帧 72 -> 45KB/帧 85 -> 70KB/帧 # 取 72:画质明显更清楚,局域网完全带得动。 "screen_quality": 72, # 默认帧率。 # 实测抓屏 33ms + 编码 17ms = 50ms,也就是**硬件上限约 20 帧/秒**。 # 原来写 3 是白白浪费了 6 倍的能力。 # 取 12:够顺,又给抓屏留了余量,不至于把 CPU 占满。 # (画面静止时会自动降频,见 screen.py 的 _loop) "screen_fps": 12,''' # ================= B2. 抓屏去重 ================= GRAB_OLD = ''' width, height = image.size if self.max_width and width > self.max_width: ratio = self.max_width / float(width) new_size = (self.max_width, max(1, int(height * ratio))) image = image.resize(new_size, Image.BILINEAR) width, height = image.size buffer = io.BytesIO() try: image.save(buffer, format="JPEG", quality=self.quality, optimize=False, subsampling=2) except Exception as exc: # noqa: BLE001 raise ScreenError(f"JPEG 编码失败: {exc}") from exc self._last_size = (width, height) return buffer.getvalue(), width, height''' GRAB_NEW = ''' width, height = image.size if self.max_width and width > self.max_width: ratio = self.max_width / float(width) new_size = (self.max_width, max(1, int(height * ratio))) image = image.resize(new_size, Image.BILINEAR) width, height = image.size # 画面没变就不编码。 # 用 32x18 的小缩略图做指纹:算一次只要 0.1ms 左右, # 但能省掉 17ms 的 JPEG 编码和之后的传输。 # 手表看静态桌面是最常见的情况,这一条省得最多。 digest = None if self.dedup: try: thumb = image.resize((32, 18), Image.BILINEAR) digest = hash(thumb.tobytes()) except Exception: # noqa: BLE001 digest = None if digest is not None and digest == self._last_digest: self._last_size = (width, height) return b"", width, height self._last_digest = digest buffer = io.BytesIO() try: image.save(buffer, format="JPEG", quality=self.quality, optimize=False, subsampling=2) except Exception as exc: # noqa: BLE001 raise ScreenError(f"JPEG 编码失败: {exc}") from exc self._last_size = (width, height) return buffer.getvalue(), width, height''' INIT_OLD = ''' def __init__(self, max_width: int = 480, quality: int = 55, monitor: int = 1): self.max_width = int(max_width) self.quality = int(quality) self.monitor = int(monitor) self._lock = threading.RLock() self._last_size = (0, 0)''' INIT_NEW = ''' def __init__(self, max_width: int = 960, quality: int = 72, monitor: int = 1, dedup: bool = True): self.max_width = int(max_width) self.quality = int(quality) self.monitor = int(monitor) # 画面没变就不重复编码(见 grab_jpeg) self.dedup = bool(dedup) self._lock = threading.RLock() self._last_size = (0, 0) self._last_digest = None''' # ================= B3. 静态降频 ================= LOOP_OLD = ''' def _loop(self) -> None: interval = 1.0 / self.fps while not self._stop.is_set(): started = time.time() try: jpeg, width, height = self.capturer.grab_jpeg() except ScreenError as exc: self.last_error = str(exc) time.sleep(0.5) continue self.frames_sent += 1 try: if self.on_frame(jpeg, width, height) is False: break # 没有观看者了,自动结束 except Exception as exc: # noqa: BLE001 self.last_error = str(exc) break elapsed = time.time() - started wait = interval - elapsed if wait > 0: self._stop.wait(wait)''' LOOP_NEW = ''' def _loop(self) -> None: interval = 1.0 / self.fps # 画面静止时把采样间隔逐级拉长(最多 4 倍),省 CPU。 # 抓屏本身就要 30ms 左右,静止时没必要一直满速抓。 idle = 1.0 while not self._stop.is_set(): started = time.time() try: jpeg, width, height = self.capturer.grab_jpeg() except ScreenError as exc: self.last_error = str(exc) time.sleep(0.5) continue if not jpeg: # 画面没变(capturer 做了去重):不发送,间隔拉长一点再抓。 idle = min(4.0, idle * 1.6) self._stop.wait(interval * idle) continue idle = 1.0 self.frames_sent += 1 try: if self.on_frame(jpeg, width, height) is False: break # 没有观看者了,自动结束 except Exception as exc: # noqa: BLE001 self.last_error = str(exc) break elapsed = time.time() - started wait = interval - elapsed if wait > 0: self._stop.wait(wait)''' # 帧率上限 15 -> 30 CAP_OLD = " self.fps = max(0.5, min(15.0, float(fps)))\n return" CAP_NEW = " self.fps = max(0.5, min(30.0, float(fps)))\n return" CAP_OLD2 = " self.fps = max(0.5, min(15.0, float(fps)))\n self._stop.clear()" CAP_NEW2 = " self.fps = max(0.5, min(30.0, float(fps)))\n self._stop.clear()" def apply(path: Path, pairs, label: str) -> bool: text = path.read_text(encoding="utf-8") ok = True for old, new in pairs: if old == new: continue if old in text: text = text.replace(old, new, 1) else: print(f" [失败] {label}: 锚点没找到 -> {old.strip()[:60]}") ok = False path.write_text(text, encoding="utf-8", newline="\n") return ok def main() -> int: ok = True # A text = RUN.read_text(encoding="utf-8") if "_tell_firewall_problem" in text: print(" A: 已经改过") else: ok &= apply(RUN, [(A_OLD, A_NEW), (HELPER_ANCHOR, HELPER_NEW)], "run_agent") print(" A: 防火墙门禁已加") # B1 text = CONFIG.read_text(encoding="utf-8") if '"screen_fps": 12' in text: print(" B1: 已经改过") else: ok &= apply(CONFIG, [(CFG_OLD, CFG_NEW)], "config") print(" B1: 默认帧率 3->12,质量 55->72") # B2 / B3 text = SCREEN.read_text(encoding="utf-8") if "self._last_digest" in text: print(" B2/B3: 已经改过") else: ok &= apply(SCREEN, [(INIT_OLD, INIT_NEW), (GRAB_OLD, GRAB_NEW), (LOOP_OLD, LOOP_NEW), (CAP_OLD, CAP_NEW), (CAP_OLD2, CAP_NEW2)], "screen") print(" B2: 加了画面去重(指纹 32x18)") print(" B3: 静止时自动降频(最多 4 倍),帧率上限 15->30") import ast for label, path in (("run_agent", RUN), ("config", CONFIG), ("screen", SCREEN)): try: ast.parse(path.read_text(encoding="utf-8")) print(f" {label} 语法 OK") except SyntaxError as exc: print(f" {label} 语法错误: 行 {exc.lineno}: {exc.msg}") ok = False return 0 if ok else 1 if __name__ == "__main__": sys.exit(main())