# -*- coding: utf-8 -*- r'''客户端长轮询超时 90 -> 120 秒。 原因(实测数据): quic+6 跑 10 次真实长轮询,出现一次 **93589ms** 的长尾。 服务端 hold 是 60 秒,也就是网络在这一次多花了 33 秒。 而客户端超时设的是 90 秒 —— 93.6 > 90,那一次**必然被判失败**, 即使服务端其实已经正常返回了。 长尾来自 4G 丢包触发的 TCP 重传退避(1.4s 的 RTT 下, 几次重传就是几十秒)。这是链路特性,改协议也消不掉, 只能把客户端的容忍度放宽。 新值:120 秒 = 60(hold) + 60(网络余量)。 Cloudflare 对单请求的上限是 100 秒,所以服务端 hold 60 秒是安全的; 客户端 120 秒只是为了不"冤枉"那些慢但成功的请求。 ''' from __future__ import annotations import sys from pathlib import Path ROOT = Path(r"C:\Users\shu\Desktop\deepseekagent\LanRemote") BOM = b"\xef\xbb\xbf" EDITS = [ ( "windows/lanremote/relay.py", """# 长轮询单次请求的超时。 # 必须显著大于服务端的 hold 时间(现在 60 秒),否则会在服务端 # 正常返回之前自己先超时 —— 那就变成"每次轮询都失败"了。 # 90 = 60 + 30 秒余量。 POLL_TIMEOUT = 90.0""", """# 长轮询单次请求的超时。 # 必须显著大于服务端的 hold 时间(现在 60 秒),否则会在服务端 # 正常返回之前自己先超时 —— 那就变成"每次轮询都失败"了。 # 120 = 60(hold) + 60(网络余量)。 # 为什么余量给这么大:实测出现过一次 93589ms 的长尾 # (4G 丢包触发 TCP 重传退避),原来设 90 秒会把它误判成失败。 POLL_TIMEOUT = 120.0""", ), ( "android/src/com/lanremote/watch/RelayTransport.java", """ /** * 长轮询:中转那边挂 60 秒,客户端超时给宽一点。 * *

必须显著大于服务端的 hold 时间,否则会在服务端正常返回 * 之前自己先超时 —— 那就变成"每次轮询都失败"了。 * 90 秒 = 60 + 30 秒余量。 */ private static final int POLL_TIMEOUT_MS = 90000;""", """ /** * 长轮询:中转那边挂 60 秒,客户端超时给宽一点。 * *

必须显著大于服务端的 hold 时间,否则会在服务端正常返回 * 之前自己先超时 —— 那就变成"每次轮询都失败"了。 * 120 秒 = 60(hold) + 60(网络余量)。 * *

余量给这么大是因为实测出现过一次 93589ms 的长尾 * (4G 丢包触发 TCP 重传退避)。设 90 秒会把那次 * 其实成功的请求误判成失败。 */ private static final int POLL_TIMEOUT_MS = 120000;""", ), ] def main() -> int: ok_all = True for rel, old, new in EDITS: path = ROOT / rel if not path.is_file(): print(" ✗ %s 不存在" % rel) ok_all = False continue raw = path.read_bytes() had_bom = raw.startswith(BOM) text = raw.decode("utf-8-sig") if old not in text: if "120000" in text or "120.0" in text: print(" • %-44s 已经是新值" % rel) continue print(" ✗ %-44s 找不到锚点" % rel) ok_all = False continue text = text.replace(old, new, 1) data = text.encode("utf-8") if had_bom: data = BOM + data path.write_bytes(data) print(" ✓ %-44s 已改" % rel) print() if not ok_all: return 1 for rel, token in ( ("windows/lanremote/relay.py", "POLL_TIMEOUT = 120.0"), ("android/src/com/lanremote/watch/RelayTransport.java", "POLL_TIMEOUT_MS = 120000"), ): text = (ROOT / rel).read_text(encoding="utf-8-sig") print(" %s %s" % ("✓" if token in text else "✗", rel)) return 0 if __name__ == "__main__": sys.exit(main())