透过源码读懂 SimpleWebTransport 版本演进:Rivet Actors Unity 示例中的 WebSocket 传输库
透过源码读懂 SimpleWebTransport 版本演进Rivet Actors Unity 示例中的 WebSocket 传输库【免费下载链接】actorsRivet Actors are the primitive for stateful workloads. Built for AI agents, collaborative apps, and durable execution.项目地址: https://gitcode.com/GitHub_Trending/riv/actors本文以 Rivet Actors 仓库中unity-demo示例所捆绑的 SimpleWebTransport 包及其 CHANGELOG.md 为核心完整梳理该包从 v1.2.2 到 v2.3.0 的全部版本记录功能、修复与破坏性变更并将每一条关键变更记录与包内 C# 源码实现逐一对照帮助读者建立“变更日志 — 参数与线程模型 — 源码位置”三层对应的阅读方法从而快速评估该传输库的能力边界与集成方式。包在仓库中的位置与基本形态SimpleWebTransport 是 Unity 生态中实现 WebSocket 协议的底层传输库在 Rivet Actors 仓库里以嵌套包nested package形式内置于 Unity 示例的 FishNet Bayou 包目录之下package.json包名com.james-frowen.simplewebtransport当前版本2.3.0要求 Unity2021.3描述为“基于 WebSocket 协议的低层 Unity 传输包含 WebSocket 服务端、独立端standalone客户端与 WebGL 客户端服务端与客户端均可用 Unity 构建”README.txt说明其可服务于 Mirror、Mirage 等高层网络方案支持 standalone 构建与 WebSocket Securewss加密CHANGELOG.md本文的分析主体覆盖 27 个发布版本源码分为三层Client/含StandAlone/与Webgl/两个平台实现、Common/收发循环、消息处理、配置、Server/服务端与握手、SSL 助手。package.json中的版本号2.3.0与 CHANGELOG 的最新条目v2.3.02025-08-02完全一致说明仓库中捆绑的正是变更日志所描述的最终版本两者可以互相印证。完整版本记录继承自 CHANGELOG 原文以下表格完整继承了原 CHANGELOG 中全部版本的日期、变更类型与描述原文中的外部 compare/commit 链接从略版本日期类型变更内容2.3.02025-08-02Feature新增获取 remotePort远端端口的函数2.2.32025-04-27Bug Fix增加 ping/pong 支持避免接收时出错2.2.22024-10-01Bug Fix改用 on 事件而非 addEventListenerWebGL 客户端2.2.12024-07-08Bug Fix增大默认的握手最大尺寸2.2.02024-04-24Feature为 SendAll 增加接受ICollection或IEnumerable的重载2.1.12024-04-09Bug Fix移除无效的自动导入2.1.02024-04-09Feature新增允许 SSL 错误的选项便于使用自签名证书测试2.0.12024-03-16Bug Fix更新包中的 Unity 版本2.0.02024-03-16破坏性变更移除全局作用域中的 Runtime不再支持 Unity 2020 及更早版本1.6.52024-03-14Bug Fix避免 WebSocket 变量进入全局作用域WebGL1.6.42023-07-15Bug Fix改进来自 opcode 的错误信息1.6.32023-06-09Bug Fix将 endpoint 转换为 IPv41.6.22023-06-08性能缓存 remoteAddress1.6.12023-06-08Bug Fix补上 mirror 示例中缺失的函数1.6.02023-06-08Feature存储全部请求头而不仅仅是部分头1.5.02023-06-08Feature新增可修改“真实 IP 头”名称的选项1.4.12023-06-08Bug Fix修正 AssemblyInfo 中的版本号1.4.02023-06-08Feature / Fix支持从反向代理获取真实 IPToString 使用 realIp1.3.22022-06-07Bug Fix在 key 头之前添加换行符1.3.12022-06-07Bug Fix请求头查找需大小写不敏感1.3.02022-02-12Feature允许最大消息尺寸提高到 int32.max1.2.72022-02-12Bug Fix修复 toString 中的 ObjectDisposedException1.2.62022-02-02Bug Fix修复 Unity 2021 下 Runtime 未定义1.2.52022-02-02Bug Fix将 Pointer_stringify 更新为 UTF8ToString1.2.42021-12-16Bug Fix为 changelog 添加 meta 文件1.2.32021-12-16Bug Fix修复 assemblyInfo 编译错误1.2.22021-12-16Bug Fix修复空 commit 导致的发布问题关键版本变更与源码实现对照下面选取变更日志中最有技术含量的几项在包内源码中定位其落地位置与实现方式。2.3.0获取远端端口的函数CHANGELOG 记录 v2.3.0 的新增能力是“get remotePort”。在服务端实现 WebSocketServer.cs 中可以确认GetClientEndPoint(int id, out string address, out int port)约 L212-L224方法按连接 id 从connections字典中取出Connection回填其remoteAddress与remotePort配套的GetClientAddress与GetClientRequest约 L226-L241分别返回地址字符串与握手阶段的Request对象。这一组查询 API 与 1.4.x 版本引入的“从反向代理获取真实 IP”特性共同构成服务端识别客户端身份的能力集。2.2.3ping/pong 支持避免接收端报错这是本包 2.2.x 序列中最重要的稳定性修复。从源码结构看其实现分布在收发两侧接收侧ReceiveLoop.cs 的ReadOneMessage中对OpCode.ping帧设置conn.needsPong true并触发conn.sendPending.Set()约 L133-L137对OpCode.pong帧则直接忽略约 L138-L140发送侧SendLoop.cs 顶部定义了预编码的 pong 帧PongResponse new byte[] { 0b1000_0000 | 10, 0 }FIN 位 PONG opcode长度 0约 L17在主循环中当conn.needsPong为真时调用SendPongResponse直接写入流约 L63-L64、L140-L144。这条变更的工程意义在于部分对端或中间代理会主动发送 ping 探活若端点不回应 pong连接可能被判定为不活跃而断开即 CHANGELOG 中“avoid error on receive”的由来。2.2.1增大握手最大尺寸服务端构造函数WebSocketServer(TcpConfig tcpConfig, int maxMessageSize, int handshakeMaxSize, SslConfig sslConfig, BufferPool bufferPool)WebSocketServer.cs 约 L26-L33中的handshakeMaxSize参数在构造ServerHandshake时传入handShake new ServerHandshake(this.bufferPool, handshakeMaxSize)。该值决定了服务端在升级握手阶段愿意缓冲的 HTTP 请求头大小v2.2.1 将其默认值调大意味着携带较多请求头长路径、多 cookie、反向代理附加头的客户端不再容易被握手阶段拒绝。结合 1.6.0 的“存储全部请求头”变更可以从 WebSocketServer.cs 的GetClientRequest看到这些头最终以Request对象形式对调用方暴露。2.1.0允许忽略 SSL 错误自签名证书测试allowSSLErrors参数贯穿客户端创建链路工厂方法SimpleWebClient.Create(int maxMessageSize, int maxMessagesPerTick, TcpConfig tcpConfig, bool allowSSLErrors false)SimpleWebClient.cs 约 L20-L27在非 WebGL 平台将其透传给WebSocketClientStandAlone构造函数WebSocketClientStandAlone.cs 的构造函数中用它初始化ClientSslHelper(allowSSLErrors)约 L20在ConnectAndReceiveLoop中执行sslHelper.TryCreateStream(conn, serverAddress)建立 wss 加密流约 L66-L72。这解释了变更日志中“Useful when testing with self signed cert”的场景本地联调时可以不配置受信任证书完成 wss 验证。2.0.0破坏性变更脱离全局作用域放弃 Unity 2020 及以下v2.0.0 的 BREAKING CHANGES 明确“no longer supports unity 2020 or earlier”与仓库内 package.json 声明的unity: 2021.3相互印证。变更背景在 1.2.6修复 Unity 2021 下Runtime is not defined与 1.6.5避免 WebSocket 变量进入全局作用域中已有铺垫WebGL 平台依赖 Emscripten 注入的全局对象如Runtime不同 Unity 版本的注入时机与命名不一致直接引用全局变量会导致 “is not defined” 运行时错误。v2.0.0 通过移除对全局Runtime的依赖来一劳永逸地解决该问题代价是抬高最低 Unity 版本。相关 WebGL 适配代码位于 Client/Webgl/SimpleWebJSLib.cs、WebSocketClientWebGl.cs与plugin/SimpleWeb.jslibv2.2.2 的 “using on events instead of addEventListener” 也落在同一 WebGL 插件层修正事件注册的 API 风格。1.3.x ~ 1.6.x请求头、真实 IP 与消息上限1.3.0最大消息尺寸提到 int32.maxmaxMessageSize是贯穿全库的核心参数。客户端基类 SimpleWebClient.cs 将其作为构造参数保存并用于初始化BufferPool(5, 20, maxMessageSize)约 L36-L41ReceiveLoop在分片消息累加时通过MessageProcessor.ThrowIfMsgLengthTooLong(totalSize, maxMessageSize)做上限检查ReceiveLoop.cs 约 L159。1.3.1 / 1.3.2头查找大小写不敏感、key 头换行两者均针对握手阶段解析 HTTP 请求与响应头的问题对应Client/StandAlone/ClientHandshake.cs与Server/ServerHandshake.cs中的头解析逻辑从源码结构看握手失败会在WebSocketClientStandAlone中打印 “Failed Handshake” 并直接 dispose 连接约 L74-L80即这类解析缺陷会直接表现为连接建立失败。1.4.0 / 1.5.0反向代理真实 IP服务端在握手阶段从请求头默认 X-Forwarded-For 一类中提取真实客户端 IP并可通过配置项更换头名称v1.6.2 进一步缓存remoteAddress以避免重复解析该缓存字段即WebSocketServer.GetClientEndPoint中直接读取的conn.remoteAddress约 L222。1.6.0存储全部请求头Connection对象携带request字段GetClientRequest(id)将其整体返回调用方可以拿到握手时的完整请求上下文。1.6.3endpoint 转 IPv4修复IPEndPoint在 IPv6 场景下解析失败的问题保证服务端 endpoint 字符串与端口提取GetClientEndPoint的out port稳定可用。配置参数与线程模型变更日志背后的实现细节变更日志中的多数“修复”都指向同一套底层机制这里结合源码给出可操作的参数说明。客户端创建参数SimpleWebClient client SimpleWebClient.Create( maxMessageSize: 1200, // 单条消息最大字节数上限可提至 int32.maxv1.3.0 maxMessagesPerTick: 200, // 每帧最多消费的消息数 tcpConfig: new TcpConfig( noDelay: true, // 禁用 Nagle降低延迟 sendTimeout: 0, // 毫秒0 表示不设超时 receiveTimeout: 0), allowSSLErrors: false); // v2.1.0 引入自签名证书测试用maxMessagesPerTick的消费逻辑见ProcessMessageQueueSimpleWebClient.cs 约 L62-L93每帧从receiveQueue出队处理处理数达到上限即停剩余消息留到下一帧防止网络突发拖住游戏主线程TcpConfigTcpConfig.cs通过ApplyTo(TcpClient)设置SendTimeout、ReceiveTimeout、NoDelay客户端与服务端acceptLoop中对每个TcpClient调用都会应用。每连接两线程 队列的收发模型从WebSocketClientStandAlone约 L88-L107与WebSocketServer约 L140-L162可以确认同一线程模型接收线程运行ReceiveLoop.Loop循环读取帧头与负载按 opcode 分发——二进制入队、close 触发conn.Dispose()、ping 标记needsPong异常SocketException/IOException/InvalidDataException 等统一转为Message(connId, exception)入队最后finally中conn.Dispose()发送线程运行SendLoop.LoopsendPending.Wait()等待唤醒优先补发 pong随后把sendQueue中的消息编码2/4/9 字节可变长度帧头见WriteHeader约 L172-L215并写流SendLoopConfig.batchSend为真时先攒到写缓冲再一次性stream.WritesleepBeforeSend为真时每轮发送前睡眠 1ms注释标明该机制是为 Mirror 的批量发送让路主线程只负责Send把数据拷入BufferPool缓冲并sendPending.Set()与ProcessMessageQueue消费事件onConnect/onData/onDisconnect/onError。服务端侧的对应关系是acceptLoop线程接受连接并为每个连接派生独立的握手接收线程连接建立成功connId分配后才启动该连接的SendLoop线程。Send(int id, ArrayBuffer)与CloseConnection(int id)都以ConcurrentDictionaryint, Connection为索引发送目标不存在时仅告警不抛异常约 L183-L210。理解这套模型后再回看变更日志多数条目都可以定位到具体机制1.6.2 的“缓存 remoteAddress”是减少接收线程中重复解析2.2.3 的 ping/pong 是跨收发两线程的协作接收线程置标志、发送线程补帧2.2.1 的握手尺寸与 1.3.x 的头解析修复都发生在接收线程开始ReceiveLoop之前的握手阶段。如何在仓库中继续深入变更日志全文CHANGELOG.md包元数据与 Unity 版本要求package.json客户端抽象基类状态机、事件、每帧消费SimpleWebClient.csStandalone 客户端连接、SSL、握手、双线程启动WebSocketClientStandAlone.csWebGL 客户端与 jslib 插件Client/Webgl/接收/发送循环与帧编解码ReceiveLoop.cs、SendLoop.cs服务端监听、握手、按 id 路由、端点/请求查询WebSocketServer.csTCP 参数结构TcpConfig.cs适用前提提示以上源码与配置均对应仓库中捆绑的 v2.3.0package.json 声明 Unity 2021.3若在其他 Unity 项目或上游仓库的其他版本中使用该传输库参数默认值与行为需以对应版本的包内容为准。【免费下载链接】actorsRivet Actors are the primitive for stateful workloads. Built for AI agents, collaborative apps, and durable execution.项目地址: https://gitcode.com/GitHub_Trending/riv/actors创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考