ykxmz 1.5.0锛氫慨澶嶆墜琛ㄧ TLS 璇佷功鏍¢獙 + MTU 淇缃戠粶绋冲畾鎬?

琚帶绔?- 淇 MTU 闂锛氬す MSS + 璺緞 MTU 鎺㈡祴锛堝叕缃戝彲鐢ㄧ巼 48% -> 100%锛?- 澶嶇敤 HTTP 杩炴帴锛堝厤鎺夋瘡娆℃柊寤?TLS 鐨?30% 鎻℃墜澶辫触锛?- 姣忓垎閽熷洖澶存壘灞€鍩熺綉锛岃嚜鍔ㄥ垏鍥炲揩 400 鍊嶇殑璺緞
- 鐢婚潰蹇冭烦甯э細闈欐鏃剁渷娴侀噺锛屽鎴风浠嶇煡閬撴祦鏄椿鐨?- 閿佸睆鏃剁粰鍑哄彲鎿嶄綔鐨勬彁绀?
鎵嬭〃绔?- 鍐呯疆 GTS Root R4 / GlobalSign Root CA锛屼慨 SSLHandshakeException
- 杩炴帴閿欒缈昏瘧鎴愪汉璇濓紙璇佷功/鏃堕棿/瑙f瀽/瓒呮椂鍒嗗埆鎻愮ず锛?- 缁忎腑杞繛涓婂悗鐢ㄦ湇鍔″櫒鎶ョ殑鍦板潃鍒锋柊宸查厤瀵硅褰?- 鏂板灞€鍩熺綉杩炴帴椤甸潰銆佹湇鍔″櫒寤惰繜妫€娴?
鏈嶅姟鍣ㄧ
- 鏀寔 chunked 璇锋眰浣擄紙淇瘡 16 绉掍竴娆$殑杩炴帴閿欎贡涓庡ぇ闈㈢Н 502锛?- 缃戠粶璋冧紭鑴氭湰 net-tune.sh锛堝紑鏈鸿嚜鍔ㄥ簲鐢級
- 绠$悊椤碉細鎵归噺鍒犻櫎銆佺綉缁滀綋妫€銆佷笅杞藉尯
- 闅ч亾鏀?HTTP/2 + 鍙岃繛鎺?
鏂囨。
- 璁稿彲鍗忚 / 瀹夎鍓嶅繀璇?/ 瀹夎鍚庨』鐭ワ紙浣滆€咃細灏忛害瀛愶級
This commit is contained in:
xmz7891
2026-10-06 19:01:05 +08:00
commit b705216e4a
3195 changed files with 203292 additions and 0 deletions
+179
View File
@@ -0,0 +1,179 @@
# -*- coding: utf-8 -*-
"""通信协议常量与编解码。
设计目标:双端零外部依赖。
* Windows 端:Python 标准库 socket + json
* 安卓端:java.net.Socket + 系统自带 org.json
传输格式:TCP 长连接,每条消息一行 UTF-8 JSON,以 \\n 结尾。
二进制负载(图片/音频/文件)用 base64 分块传输。
"""
from __future__ import annotations
import base64
import json
DEFAULT_PORT = 8765
PROTOCOL_VERSION = 1
MAX_LINE_BYTES = 8 * 1024 * 1024 # 单行上限 8MB(约 6MB 原始数据)
CHUNK_SIZE = 256 * 1024
# 单次传输(文件 / 图片 / 音频)的总体积上限
MAX_TOTAL_BYTES = 256 * 1024 * 1024 # 分块大小 256KB
# ---- 客户端 -> 服务端 命令 ----
CMD_PAIR = "pair"
CMD_AUTH = "auth"
CMD_PING = "ping"
CMD_IMAGE = "image"
CMD_AUDIO = "audio"
CMD_MEDIA = "media"
CMD_CLIP_SET = "clip_set"
CMD_CLIP_GET = "clip_get"
CMD_POWER = "power"
CMD_RUN = "run"
CMD_SAY = "say"
CMD_VOICE_LIST = "voice_list"
CMD_SET_VOICE = "set_voice"
CMD_AUDIO_LIST = "audio_list"
CMD_PLAY_LOCAL = "play_local"
CMD_SHUTDOWN_TIMER = "shutdown_timer" # 定时关机 / 取消
CMD_MONITOR = "monitor" # 关闭 / 打开显示器
CMD_OPEN_URL = "open_url" # 在电脑浏览器打开网址
CMD_QUICK = "quick" # 快捷启动程序
CMD_OPEN_FOLDER = "open_folder" # 打开常用文件夹
CMD_PROC_LIST = "proc_list" # 进程列表
CMD_PROC_KILL = "proc_kill" # 结束进程
CMD_BATTERY = "battery" # 电量
CMD_DISK = "disk" # 磁盘占用
CMD_PERF = "perf" # CPU / 内存占用
CMD_CLIP_HISTORY = "clip_history" # 剪贴板历史
CMD_SET_WALLPAPER = "set_wallpaper" # 把收到的图设为壁纸
CMD_SAY_CLIP = "say_clip" # 朗读剪贴板
CMD_FEATURE_LIST = "feature_list" # 电脑端能做哪些功能
CMD_FEATURE_RUN = "feature_run" # 执行某个功能
CMD_AUDIO_PAUSE = "audio_pause" # 暂停电脑正在播的音频
CMD_AUDIO_RESUME = "audio_resume" # 继续播放
CMD_AUDIO_STATUS = "audio_status" # 当前播放状态
CMD_NOTIFY = "notify"
CMD_FILE_PUSH = "file_push"
CMD_FILE_LIST = "file_list"
CMD_FILE_PULL = "file_pull"
CMD_INFO = "info"
CMD_SCREEN_START = "screen_start"
CMD_SCREEN_STOP = "screen_stop"
CMD_SCREENSHOT = "screenshot"
# ---- 服务端 -> 客户端 事件 ----
EVT_FILE = "file"
EVT_CLIP = "clip"
EVT_STATUS = "status"
EVT_LOG = "log"
EVT_FRAME = "frame"
EVT_SCREEN_STOPPED = "screen_stopped"
MEDIA_ACTIONS = {
"playpause": 0xB3,
"next": 0xB0,
"prev": 0xB1,
"stop": 0xB2,
"volup": 0xAF,
"voldown": 0xAE,
"mute": 0xAD,
}
POWER_ACTIONS = {"shutdown", "restart", "lock", "sleep", "abort"}
# 手表端会用到的中文动作名(便于 UI 直接显示)
MEDIA_LABELS = {
"playpause": "播放/暂停",
"next": "下一曲",
"prev": "上一曲",
"stop": "停止",
"volup": "音量+",
"voldown": "音量-",
"mute": "静音",
}
POWER_LABELS = {
"shutdown": "关机",
"restart": "重启",
"lock": "锁屏",
"sleep": "睡眠",
"abort": "取消关机",
}
def dumps(obj: dict) -> bytes:
"""编码成一行 JSON(UTF-8 + 换行)。"""
return (json.dumps(obj, ensure_ascii=False, separators=(",", ":")) + "\n").encode("utf-8")
def loads(line: bytes) -> dict:
"""解析一行 JSON。"""
return json.loads(line.decode("utf-8", errors="replace").strip())
def b64encode(data: bytes) -> str:
return base64.b64encode(data).decode("ascii")
def b64decode(text: str) -> bytes:
return base64.b64decode(text.encode("ascii"))
def chunk_bytes(data: bytes, size: int = CHUNK_SIZE):
"""把字节流切成若干块,产出 (seq, is_last, chunk)。"""
if not data:
yield 0, True, b""
return
total = (len(data) + size - 1) // size
for index in range(total):
piece = data[index * size:(index + 1) * size]
yield index, index == total - 1, piece
class ChunkTooLarge(Exception):
"""分块累积超过上限,或顺序不对。"""
class ChunkAssembler:
"""接收端:按 seq 收集分块,拼回完整数据。
MAX_LINE_BYTES 只管单行,累积体积必须另外设上限 ——
否则已配对设备可以一直发 chunk 把内存吃干(最后 bytes() 还要再翻一倍)。
"""
def __init__(self, limit: int = MAX_TOTAL_BYTES):
self._buf = bytearray()
self._expected = 0
self._limit = int(limit)
def feed(self, seq: int, is_last: bool, data: bytes) -> bytes | None:
"""返回完整数据(当收到最后一块时),否则 None。
顺序不对或超限时抛 ChunkTooLarge,不静默拼出坏文件。
"""
if seq == 0:
self._buf = bytearray()
self._expected = 0
if seq != self._expected:
self._buf = bytearray()
self._expected = 0
raise ChunkTooLarge(
f"分块顺序不对(收到 {seq},应为 {self._expected})")
if len(self._buf) + len(data) > self._limit:
self._buf = bytearray()
self._expected = 0
raise ChunkTooLarge(f"文件超过上限({self._limit // 1048576} MB)")
self._buf.extend(data)
self._expected = seq + 1
if is_last:
result = bytes(self._buf)
self._buf = bytearray()
self._expected = 0
return result
return None
def reset(self) -> None:
self._buf = bytearray()
self._expected = 0