TG WS Proxy源码解析:RawWebSocket如何用asyncio从零手写高性能WSS客户端

发布时间:2026/9/1 14:07:38
TG WS Proxy源码解析:RawWebSocket如何用asyncio从零手写高性能WSS客户端 TG WS Proxy源码解析RawWebSocket如何用asyncio从零手写高性能WSS客户端【免费下载链接】tg-ws-proxyLocal MTProto proxy server for partial bypassing of Telegram loading项目地址: https://gitcode.com/gh_mirrors/tg/tg-ws-proxyTG WS Proxy是一个运行在本地的 Telegram MTProto 代理通过把 Telegram Desktop 的流量转入 WebSocketWSS通道来加速和保活连接。它的核心亮点之一是在 proxy/raw_websocket.py 中不依赖任何第三方 WebSocket 库仅用 Python 标准库asynciosslstruct从零手写了一个完整的 WSS 客户端。本文带你拆解它的设计与性能技巧。一、为什么手写 WSS 客户端大多数 Python 项目做 WebSocket 会直接引入websockets或aiohttp之类的依赖。但 TG WS Proxy 的目标是零额外依赖pyproject.toml 的运行时依赖里没有 WebSocket 库只有asyncio标准库可用只做必要的事作为代理它不需要完整的 RFC 6455 语义分片、扩展头等只需要BINARY / PING / PONG / CLOSE四种帧极致可控连接对象极轻可以被连接池批量创建、轮换、复用。于是整个 WebSocket 实现只有 270 行左右却覆盖了握手、帧编解码、掩码处理、心跳和关闭协商。二、类结构设计一个只持有两个引用的轻量对象RawWebSocket类定义在 proxy/raw_websocket.py#L69-L81核心状态只有三个class RawWebSocket: __slots__ (reader, writer, _closed)直接复用asyncio.open_connection()返回的StreamReader / StreamWriter不自己管理传输层使用__slots__消除实例__dict__在连接池动辄几十上百个连接的场景下显著降低内存占用。三、连接与 HTTP 升级握手connect()静态方法连接流程见 proxy/raw_websocket.py#L83-L148步骤清晰TLS 建连asyncio.open_connection(host, 443, ssl_ssl_ctx, server_hostnamesni)一步完成 TCP TLSSNI 可独立于 Host 指定用于 fronting 场景见 proxy/pool.py#L181-L190发送 Upgrade 请求手写 7 行 HTTP 头携带Sec-WebSocket-Key16 字节随机数 Base64逐行读取响应用reader.readline()循环读到空行为止兼容有/无 Content-Length 的响应状态码分流101 Switching Protocols→ 返回RawWebSocket实例握手成功301/302/...→ 抛出WsHandshakeError并携带Location上层据此判断被 302 重定向并触发降级其他 → 解析响应头后抛错便于排障。整个握手全程被asyncio.wait_for包裹超时控制任何一步卡死都不会拖垮连接。四、帧编解码struct 预编译 整数异或的两个加速点4.1 帧构建_build_frame()帧的构造在 proxy/raw_websocket.py#L235-L252头部格式预编译文件顶部一次性编译好_st_BB、_st_BBH、_st_BBQ等 7 个struct.Struct对象#L15-L22pack()时免去每次解析格式串这是典型的把常量提到热循环外优化三档长度编码按 RFC 6455 分别处理 126、65536、64 位长度三种头部形态掩码客户端帧必须掩码os.urandom(4)生成掩码键。4.2 掩码异或_xor_mask()proxy/raw_websocket.py#L43-L49 的写法很有味道return (int.from_bytes(data, big) ^ int.from_bytes(mask_rep, big)).to_bytes(n, big)它把整个 payload 转成大整数做一次异或代替逐字节循环。对几 KB 大小的 MTProto 包C 层的任意精度整数运算比 Python 层的bytes拼接快得多这是全文件最炫技的一处优化。4.3 帧读取_read_frame()读帧逻辑在 proxy/raw_websocket.py#L254-L267reader.readexactly(2)取头 → 视长度字段补读 2 或 8 字节扩展长度 → 有掩码位则补读 4 字节掩码并解掩。readexactly保证要么拿全、要么抛IncompleteReadError配合上层的asyncio.wait_for超时断连场景下行为可预期。五、收发的健壮性recv()的帧循环recv()#L165-L198不是一次读取就返回而是一个while 循环过滤控制帧收到OP_CLOSE记录关闭码并回发关闭帧_parse_close会把 1006、1011 等码映射成可读原因名返回None通知上层收到OP_PING自动回PONG后continue对上层透明收到PONG静默丢弃收到文本/二进制帧返回 payload。同时提供send_batch(parts)#L157-L163把多个分片逐个构帧后一次性drain减少await往返次数适合批量转发 MTProto 消息块。六、TCP 层的隐藏优化set_sock_opts()除了应用层proxy/raw_websocket.py#L52-L66 在建连后立即调整套接字TCP_NODELAY关闭 Nagle 算法小消息立刻发出——代理场景全是小帧这条直接影响延迟SO_RCVBUF / SO_SNDBUF按配置默认 256KB见--buf-kb调整收发缓冲缓解突发流量。七、与连接池协作为什么这个小客户端够快RawWebSocket单独看只是一个轻量协议实现它的性能上限来自 proxy/pool.py 的连接池设计预热warmup()在服务启动时就为每个 DC 预建pool_size默认 4条 WSS 连接借用即补get()命中空闲连接后立即_schedule_refill()异步补位客户端拿到的永远是新鲜连接老化轮换连接存活超过 120 秒WS_POOL_MAX_AGE即关闭重建避免长连接被上游掐断指数退避补建失败时按 60s → 120s → ... 最多 1 小时退避不轰炸上游。正因为RawWebSocket没有重量级内部状态、创建成本低池化策略才能成立。八、主流程中的位置从 MTProto 握手到 WSS 隧道完整链路在 proxy/tg_ws_proxy.py 的_handle_client()#L250-L458中串起来读取客户端 64 字节 obfuscation init用secret派生密钥解密出DC ID_try_handshake生成新的 relay init 与四路 AES-CTR 加解密器_build_crypto_ctx纯 Python 实现的 proxy/_aes.py优先从ws_pool取连接未命中则RawWebSocket.connect(target_ip, domain)直连 Telegram 官方 WSS 端点域名列表见 proxy/utils.py#L59-L64 的ws_domains()失败自动降级302 全被重定向 → 拉黑 WS 走 TCP 直连超时 → IP 冷却 1 小时再不行走 Cloudflare 代理/Worker 回源隧道打通后交给 proxy/bridge.py 的bridge_ws_reencrypt()做双向解密-重加密-封帧转发。也就是说RawWebSocket负责把 WSS 通道稳稳建起来pool.py负责让它永远有库存bridge.py负责让字节流正确穿越隧道三者分工清晰。九、文件导航快速定位关键代码模块职责proxy/raw_websocket.py手写 WSS 客户端握手、帧编解码、心跳proxy/pool.pyWSS 连接池预热、补位、老化轮换、退避proxy/tg_ws_proxy.py主流程监听、MTProto 握手、降级策略proxy/bridge.py双向加解密转发re-encryptproxy/_aes.py纯 Python AES 实现proxy/config.py运行参数与 DC 配置十、小结TG WS Proxy 的RawWebSocket是一次很好的标准库极限运用示范克制只实现用到的 4 种帧270 行覆盖完整 WSS 客户端⚡微优化叠加struct预编译、大整数异或、__slots__、TCP_NODELAY、批量drain每处都小合力显著可池化轻量无状态的设计是连接池策略成立的前提这也是它高性能的真正来源。对想深入 asyncio 网络编程的同学这份代码是一份难得的、可以直接逐行阅读的小型生产级范例。【免费下载链接】tg-ws-proxyLocal MTProto proxy server for partial bypassing of Telegram loading项目地址: https://gitcode.com/gh_mirrors/tg/tg-ws-proxy创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考