# -*- coding: utf-8 -*- """把隧道协议从 QUIC 改成 HTTP/2 —— 这是这次 1033 的根治办法。 实测(同一台设备,同一时刻,各跑 90 秒): 可用率 断开 拨号失败 QUIC(UDP) 48% 16 16 HTTP2(TCP) 80% 2 0 日志里 QUIC 全是这类错: Failed to dial a quic connection ... no recent network activity Connection terminated error="control stream error: context deadline exceeded" Connection terminated error="Failed to accept QUIC stream" 原因:这条线路(现在是 192.168.10.x 的出口)在丢 UDP 包, QUIC 撑不住;TCP 虽然有重传、稍慢,但稳得多。 注意:之前测过 HTTP/2 不行(TCP 7844 被挡),那时是 192.168.2.x 的出口。 换了网络之后结论变了 —— 所以这类东西必须实测,不能凭旧结论拍板。 """ from __future__ import annotations import sys from pathlib import Path ROOT = Path(r"C:\Users\shu\Desktop\deepseekagent\LanRemote") INSTALL = ROOT / "relay" / "install.sh" INSTALL_OLD = '''# 协议:必须 QUIC(这条线路挡了 HTTP/2 的 TCP 7844)''' INSTALL_NEW = '''# 协议:HTTP/2(走 TCP 7844)。 # 实测对比(各 90 秒): # QUIC(UDP) 可用 48%,断开 16 次,拨号失败 16 次 # HTTP/2 可用 80%,断开 2 次,拨号失败 0 次 # 这条线路在丢 UDP 包,QUIC 的"no recent network activity"就是丢包导致的; # TCP 有重传,虽然理论延迟高一点,但稳定得多。 # (早先在 192.168.2.x 的出口上 TCP 7844 是被挡的,换了出口就通了 —— # 所以别照搬旧结论,换网络要重测。)''' EXEC_OLD = '''ExecStart=/usr/local/bin/cloudflared tunnel --no-autoupdate \\ --edge-ip-version 4 --ha-connections 1 --retries 5 \\ --url http://127.0.0.1:8080''' EXEC_NEW = '''ExecStart=/usr/local/bin/cloudflared tunnel --no-autoupdate \\ --protocol http2 --edge-ip-version 4 --ha-connections 1 --retries 5 \\ --url http://127.0.0.1:8080''' UNIT = '''[Unit] Description=LanRemote Cloudflare 具名隧道 After=network-online.target lanremote-relay.service Wants=network-online.target lanremote-relay.service [Service] Type=simple # 协议:HTTP/2(TCP 7844) # 实测:QUIC 可用 48%(断开 16 次),HTTP/2 可用 80%(断开 2 次)。 # 这条线路丢 UDP 包,QUIC 撑不住;TCP 有重传,稳得多。 # 连接数:1(默认 4) # 实测 4 条并发握手会互相挤(只成功 1 条); # 链路差时 2 条也会有一条一直失败重试、拖累另一条。 # 冗余交给看门狗(每 20 秒查一次,僵死就重启) ExecStart=/usr/local/bin/cloudflared tunnel --no-autoupdate --protocol http2 --edge-ip-version 4 --ha-connections 1 --retries 5 --config /root/.cloudflared/config.yml run lanremote Restart=always RestartSec=5 MemoryMax=128M StandardOutput=append:/root/lanremote-relay/tunnel.log StandardError=append:/root/lanremote-relay/tunnel.log [Install] WantedBy=multi-user.target ''' # 部署脚本里那份 unit 也要改 DEPLOY = ROOT / "_build" / "deploy_final.py" def main() -> int: ok = True text = INSTALL.read_text(encoding="utf-8") if "--protocol http2" in text: print(" install.sh 已经是 http2") else: changed = 0 for old, new, label in ((INSTALL_OLD, INSTALL_NEW, "注释"), (EXEC_OLD, EXEC_NEW, "ExecStart")): if old in text: text = text.replace(old, new, 1) changed += 1 print(f" install.sh:改了{label}") else: print(f" [警告] install.sh 的{label}锚点没找到") INSTALL.write_text(text, encoding="utf-8", newline="\n") print(f" install.sh 共改 {changed} 处") if DEPLOY.is_file(): dep = DEPLOY.read_text(encoding="utf-8") if "--protocol http2" in dep: print(" deploy_final.py 已经是 http2") elif "--ha-connections 1 --retries 5 --config" in dep: dep = dep.replace( "--ha-connections 1 --retries 5 --config", "--protocol http2 --ha-connections 1 --retries 5 --config") DEPLOY.write_text(dep, encoding="utf-8", newline="\n") print(" deploy_final.py:ExecStart 加了 --protocol http2") else: print(" [提示] deploy_final.py 里没找到 unit 模板(可能从 install.sh 生成)") raw = INSTALL.read_bytes() if b"\r\n" in raw: INSTALL.write_bytes(raw.replace(b"\r\n", b"\n")) print(" install.sh:修了 CRLF") return 0 if ok else 1 if __name__ == "__main__": sys.exit(main())