解决MySql布尔型新旧版本兼容问题,采用枚举来表示布尔型的数据表。由正向工程赋值
大石头 authored at 2018-05-15 21:21:05
18.37 KiB
X
# 网络库架构 > 适用范围:NewLife.Core 的 `NewLife.Net`、`NewLife.Messaging`、`NewLife.Data`(数据包部分)与 `NewLife.Http`(服务端)。 > 目标形态:简单架构覆盖 80% 日常场景,剩余 20% 通过明确的扩展点留给下游。 > 配套专题:《数据包IPacket》《数据管道Pipe》《网络缓冲所有权架构》《消息协议栈》《高级二进制序列化》。 > **v12 过渡说明**:§1-§5 已按新协议栈更新;§6 处置表为 2026-09 历史收敛记录(现行结论见《消息协议栈》§7)。 ## 1. 分层与数据通路 ``` 应用层 NetServer / NetSession / NetClient ↑ 消息与事件 协议层 IMessageCodec(SrmpCodec / LengthFieldCodec / SplitDataCodec / WebSocketCodec) ↑ 消息(IMessage) 帧泵 MessagePump(管道上定界与交付;头到齐即交付,体流式/内存统一) ↑ 字节流 缓冲层 Pipe(窗口 + 背压) | 每轮拥有句柄(SessionBase 轮末裁决) ↑ 传输层 SessionBase / TcpSession / TcpServer / UdpServer / UdpSession ↑ 接入面 Socket(内置监听与连接) | 外部 Socket 接管(客户端 TcpSession(Socket)) ``` **接收数据流(简)** 1. Socket 读回调进入 `SessionBase.ProcessEvent`:本轮数据包装为拥有句柄(`OwnerPacket`),轮末按引用计数裁决——`RefCount==1` 时 `Detach` 复用缓冲,否则归还换新(零 Rent/Return 快路径)。 2. 连接型会话(`TcpSession`)把本轮数据追加进数据管道(`Pipe`,有界背压);UDP 数据报即完整帧,直接逐条分发。 3. 定界:协议模式由 `MessagePump` 从管道定界交付(头到齐即交付,体为内存视图或流式);UDP 一跳多帧无粘包处理。 4. 消息回流到会话:`Received` 事件 → `NetSession` → 可选的 `INetHandler`(如 `HttpSession`)→ `NetServer.Received`。 **接收模式(二选一)**:打开前设置 `AutoReceive`(`SessionBase`,默认 true)——true 自动启动接收环走事件推送(接收环运行期间 `Receive/ReceiveAsync` 抛出异常);false 只允许拉取直读。两模式互斥;拉取模式下可调用无参 `ReceiveAsync()` 手动转事件模式(单向,不回退)。WebSocket 握手发生在打开过程的接收环启动之前,直读天然合法。 **发送数据流**:`Send` → 协议构建整帧(`Build`/`BuildHeader` + 流式体)→ Socket(或 SSL `_Stream`)→ 网卡。 ## 2. 80% 黄金用法 ### 2.1 服务端 + 编解码 ```csharp class MyServer : NetServer<MySession> { } class MySession : NetSession<MyServer> { protected override void OnReceive(ReceivedEventArgs e) { var pk = e.Packet; // 当前指令的数据帧 if (pk == null || pk.Length == 0) return; Send(pk); // 回发 } } var server = new MyServer { Port = 0 }; server.Protocol = new SrmpCodec(); // 或 LengthFieldCodec / SplitDataCodec / CompressedCodec / 自定义 server.Start(); ``` - 内置协议:`SrmpCodec`(新生命标准封包)、`LengthFieldCodec`(长度字段,MQTT 风格)、`SplitDataCodec`(分隔符)、`CompressedCodec`(压缩装饰器,可组合)。 - 也可以不定义会话子类,直接 `server.Received += ...` 集中处理。 ### 2.2 客户端 ```csharp var client = new NetUri("tcp://127.0.0.1:1234").CreateRemote(); client.Protocol = new SrmpCodec(); client.Open(); client.Send("Hello".GetBytes()); ``` - 请求-响应:`SendMessageAsync`,由会话匹配队列(按协议 `IMessageMatcher` 配对)完成应答配对。 - 断线重连等应用级能力可使用 `NetClient`。 - 纯拉取客户端(Modbus/短连接请求-响应风格):打开前设 `client.AutoReceive = false`,用 `Receive()/ReceiveAsync(ct)` 直读 Socket。 ### 2.3 自定义协议 - 实现 `IMessageCodec`(`TryParse` 定界构造 / `Build` 整帧 / `BuildHeader` 头部);参考 `Messaging/SrmpCodec.cs` 与 `LengthFieldCodec.cs`。 - 协议实例须无状态(可跨连接共享);可经 `CompressedCodec` 等装饰器组合变换层(压缩/加密),无需多层管道。 ### 2.4 流式协议(新协议推荐) - 连接型会话(`TcpSession`,接口 `IStreamSession`)的 `Pipe` 懒建:`Pipe` 承载字节流窗口与背压,`MessagePump` 定界交付消息(头到齐即交付,体流式/内存统一,跨轮等待)。 - 出站方向:`TcpSession.SendPipe` 懒建(创建后 `Send` 系列单出口入管道;发送泵为内部组件 `SendPump`,批量送出),写侧 `FlushAsync(waitForResume:true)` 获得发送回压,关闭时先排空再关连接;`TcpSession.SendAsync(Stream)` 流式发送(分块零拷贝入管道),大文件不整段驻留;消息协议头 + 流式体:`codec.BuildHeader(msg, length)` 声明长度后接 `SendAsync(Stream)`。 - 传输层大负载:HTTP 响应体 `HttpResponse.BodyStream`(可寻址流→Content-Length,未知长度→`Transfer-Encoding: chunked`;静态文件/嵌入资源已接入,大文件不物化);WebSocket 大帧经 `WebSocketCodec` 构建。 - 细节与示例见《数据管道Pipe》。 ### 2.5 消息契约(IMessage / IMessageCodec) - 消息契约 `IMessage`:`MessageKinds Kind` 四态(与 SRMP 头高 2 位对应,`Reply`/`OneWay` 便捷视图)、`Payload`(消息体句柄视图,流式为 null)、`Body`(内存视图或限长流式读取器)、`SetBody`/`BindBody`、`CreateReply`(应答上返回 null)、`Dispose`。 - 协议契约 `IMessageCodec`:`TryParse`(定界并构造消息,头部不足返回 null)、`Build`(整帧构建,转移语义:构建后消息不再持有体)、`BuildHeader`(头 + 流式体);无状态可跨连接共享。请求-响应配对经 `IMessageMatcher`(如 SRMP 按序列号)。 - 帧定界/构建完全由协议对象承担,消息不感知帧字节;可组合装饰器(如 `CompressedCodec`)实现变换层。并行处理见 `MaxConcurrency`。详见《消息协议栈》。 ## 3. 20% 扩展点目录 | 深度 | 扩展方式 | 关键类型 | |:----:|----------|----------| | 1 | 自定义协议 | 实现 `IMessageCodec`;`server.Protocol = ...` 设置 | | 2 | 自定义会话 | `NetServer<TSession>` / `NetSession<TServer>`;override `OnConnected / OnDisconnected / OnReceive` | | 3 | 会话级业务处理器 | `INetHandler`(`NetServer.CreateHandler` 返回,如 HttpServer → HttpSession) | | 4 | 请求响应匹配策略 | `IMatchQueue`(`DefaultMatchQueue.Add / Match` 可重载) | | 5 | 接管外部 Socket | 客户端 `new TcpSession(socket)` + `Open()`(跳过连接直接收发);服务端暂无接管入口,对外部服务器对象用 `NetServer.AttachServer(ISocketServer)` 挂接(见下行) | | 6 | 自定义传输 | `ITransport`(帧传输抽象,串口/自定义链路接入);`NetServer.AttachServer(ISocketServer)` 挂接自定义服务器 | | 7 | 数据管道回调 | `TcpSession.CreatePipe` 重载(`IStreamSession`);`MessagePump.ReadAsync` | ## 4. 交付上下文契约(数据可带上传输对象) - 协议层/处理器:事件参数(`ReceivedEventArgs`,裸模式含 `INetHandler` 旁路)可回溯到会话对象(`ISocketRemote`);裸 Socket 经 `ISocket.Client` 获取。 - 应用层:`NetSession.Session`(`ISocketSession`)→ `ISocket.Client` 获取底层 Socket;`Remote/Local` 等地址信息同源。 - 接管场景:`TcpSession(Socket)` 接管后,会话的 `Client` 即为调用方传入的 Socket;客户端接管会话的 `ISocketSession.Server` 为空。 - 原则:不新增平行的数据上下文对象;所有投递入口(`Received` 事件、`INetHandler`、流式消息体)都在会话作用域内执行,可回溯到会话与传输对象。 ## 5. 帧引擎(v12 单引擎) v12 已整删旧双引擎(`PacketCodec`/`PacketFramer`),统一为 `MessagePump`:管道上定界交付(头到齐即交付、小帧零拷贝快路径、大帧流式体、`MaxCache` 残余防护),协议经 `IMessageCodec` 无状态实现。历史双引擎选型与冻结决策见本文件 git 历史(2026-09-16 记录)。 ## 6. 概念处置表(v12 收敛) | 抽象 | 处置 | 状态 | |------|------|:----:| | `SessionBase` | 保留为 TCP/UDP 共用报文核心;字节流管道与单出口发送队列下放 `TcpSession` | ✅ 2026-09-17 | | `SessionBase.MaxAsync` | 三义拆分删除:接收模式由 `AutoReceive` 二选一(true=接收环事件模式、false=拉取直读);并发待收数内部化(TCP 1,UdpServer 默认 CPU×1.6,`UdpServer.MaxAsync` 可调) | ✅ 2026-09-18 | | 流式收发(`Pipe`/`SendPipe`/`SendAsync(Stream)`) | 从 `SessionBase` 全部下放 `TcpSession`(新接口 `IStreamSession` + internal `SendPump` 泵):发送分流并入 `OnSend`、轮数据投递并入 `OnPreReceive`、背压暂停并入 `OnReceiveAsync`、关闭收尾并入 `CloseAsync` 重写;基类不保留任何流式概念 | ✅ 2026-09-17 | | `ITransport` | 保留:下游已有实现者(Modbus `UdpTransport`、XCom `SerialTransport`),定位为"自定义传输"扩展点 | ✅ 2026-09-16 生态扫描确认 | | `TcpServer.EnableHttp` | 死开关(只写不读),已删除;HTTP 由 `HttpServer.CreateHandler` 在处理器管道处理 | ✅ 2026-09-25 已删除(生态源码扫描零引用) | | `PacketCodec` | 评估"单一引擎外观化"(内部复用 Pipe + PacketFramer),带验证门;未达标则冻结为遗留路径。评估结论:带验证门条件不可达(见 §5),冻结为存量协议与旧二进制兼容面 | ✅ 2026-09-16 | | `IMessage` | 保留消息契约;消息不再池化口径已统一(内置消息直接 new,工厂池化定位为自定义消息的可选能力)。`IMessage` 继承帧契约 `IFrameMessage`(v12 破坏性变更:旧名 `Read/ToPacket/ToHeaderPacket` 桥删除,下游改 `ReadFrame/Build/BuildHeader` 并重新编译) | ✅ 2026-09-18 | | `Message` 响应语义 | 收敛为 `MessageKinds Kind` 单枚举(请求/单向/响应/响应+错误,与协议状态位一一对应);`Reply`/`OneWay` 为便捷视图(get 由 Kind 推导,set 回写 Kind),不再三布尔独立存储 | ✅ 2026-09-25 | | `DefaultMessage` 构建契约 | `Build` 非破坏性:构建不改动消息负载,`message.Payload` 之后依然可用;已预留的负载向前借位共享(零拷贝),其余以新头节点挂接负载链(拥有句柄先切为独占共享链)。返回 `IOwnerPacket` 供调用方 `using` 释放 | ✅ 2026-09-25 | | 具体包类型的反序列化识别 | 反序列化(读路径)只识别 `typeof(IPacket)`——物化必须由调用方指定明确的接口类型;序列化(写路径)继续用 `type.As<IPacket>()`(任何实现都能写出)。删除 `Packet` 后不再对具体包类型做特例,生态统一改用 `IPacket` | ✅ 2026-09-25 | | `HttpHelper.ParseHeader` | 依赖 `Packet` 的可变 API(`Set/Data/Count`),且全仓与生态零调用 → 随类删除;不新建推测性替代 API | ✅ 2026-09-25 | | `IPacket.FreeHeader` 借位前提 | 仅对拥有句柄借位;写入的是本视图之前的字节,仅当这些字节空闲(预留区、或解析所得帧头已消费)时才安全。调用方自造的非帧边界拥有句柄不满足该前提——只做文档约束,不加运行期防护(否则会切断零拷贝收益) | ✅ 2026-09-25 | | `WebSocketMessage` | 独立化:不再继承 `Message`、不实现 `IMessage`,直接实现 `IFrameMessage`;v12 删除旧名桥(`Read/ToPacket/ToHeaderPacket`),保留 `Payload`;引用方需重新编译适配 | ✅ 2026-09-18 | | `IPipeline` / `Handler` | 保留(注册与处理链);明确与 `INetHandler` 的职责边界 | 🔧 待文档 | | `UdpSession` | 收敛评估已完成(见附录 A):暂不实施,优先抽取共享发送/日志/错误助手而非继承 | ✅ 2026-09-16 | | WebSocket 双实现(`Http/WebSocket` 与 `Net/Handlers/WebSocketCodec`) | 已互相定位注释(HTTP 升级路径 vs Net 侧通用编解码),合并留后续 | ✅ 2026-09-16 | | `NetClient` | 保留(应用级起步封装) | ✅ | | `Bin/` 陈旧文档副本 | 清理(与 `Doc/` 同名且落后) | ✅ 2026-09-16 | ## 7. 兼容纪律(改动本库前必读) - 公开 API 的删除、改名、返回类型收窄都会断开旧二进制(CLR 成员引用绑定包含返回类型);优先新增成员。 - `[Obsolete]` 壳(三参 `Slice`、`OwnerPacket.Free`)已按 v12 破坏性清单删除;旧版编译的调用方(如 Remoting 的三参 `Slice`)会抛 `MissingMethodException`,需随大版本重编译发版。 - 变更公开面后的默认门禁:全 18 TFM 编译(含 net45)+ 全量测试 + 生态扫描(`C:\X` 下游仓库与 NuGet 缓存 `newlife.*` 产物)。 ## 8. 文档索引 - 数据与帧:《数据包IPacket》《数据管道Pipe》《数据包编码器PacketCodec》《网络缓冲所有权架构》《高级二进制序列化》 - 同步/异步:《网络库同步异步分工》(双轨决策、场景选型、发送架构:直发 vs 发送泵) - 标准封包:`NewLife.Core/Net/Readme.md`(SRMP) - 用法样例:`Samples/Zero.EchoServer`、`Samples/Zero.Server`;基准:`Benchmark/NetBenchmarks`、`Benchmark/PacketBenchmarks` - 三件套(架构设计 / 功能清单 / 需求文档)为 v11 时期文档,v12 定稿时统一同步。 ## 9. 未决架构项(2026-09-25 评估,待决策) 以下项属"结构性收敛",改动会触及协议契约或生态二进制,**未随缺陷修复批次实施**。按此顺序推进,每项独立可验证: | 项 | 现状 | 前置决策 | |---|---|---| | codec 能力显式化(B2) | `IMessageCodec` 三成员实为"部分协议支持";装饰器能力已用 `IMessageCodecDecorator` 逐层解包(已完成该部分) | 是否允许给 `IMessageCodec` 加成员/加继承(`IMessage` 不动)。生态实现者需随大版本重编 | | 帧定界与交付编排(B5) | `SessionBase.ProcessMessageAsync` 与 `UdpSession.ProcessDatagram` 是两套实现,行为已漂移(UDP 无配对、无 `DiscardAsync` 收尾) | 建议先补 UDP 收尾对齐,再抽 `MessageDispatcher` 统一交付编排 | | WebSocket 双帧循环(B12) | 服务端 `Http/WebSocket.Process` 与客户端 `WebSocketClient.OnReceivedMessage` 各写一套帧循环(客户端已统一为整帧交付) | 是否接受新增 `WsFrameLoop` 类型并下沉到 Messaging | | `SessionBase` 瘦身(B9) | 基类仍带流式专有状态(`MaxCache`/`MatchQueue`/`MaxConcurrency`/`RequireFullFrame`),UDP 继承却不用 | 下沉 `TcpSession` 或抽 `IMessageSession`;会触及 `ISocketSession`/`ITransport` 实现者,需生态发版节奏 | | 事件体系收敛(B7) | `EventHub` 兼协议解码 + 路由 + 5 个 `[Obsolete]` 成员;`IEventBus` 自称"仅类型标记"却含 `PublishAsync`;`IAsyncEventBus` 为空别名 | 删除公开类型/成员前需生态扫描(`git grep` 逐仓,全仓递归遍历在本机常态超时) | > 说明:`HTTP` 服务端"整请求缓冲 + 同步阻塞派发"(`ExecutePipeline(...).GetAwaiter().GetResult()`)与 `DefaultHttpContext.Current` 的 `[ThreadStatic]` 取上下文,属能力级改造(handler 契约升级为异步),已单列,不并入上表。 ### 9.1 逐项结论(2026-09-25 决策) | 项 | 结论 | 依据 | |---|---|---| | B2 codec 能力显式化 | **不做接口变更** | `IMessageCodec` 是生态实现最多的接口,加成员/加继承会断全部实现者。能力表达已有三条既有通道:`IMessageMatcher`(配对)、`IMessageCodecDecorator`(装饰器逐层解包)、明确的 `NotSupportedException` 文案;本会话已补"能力矩阵"文档段 | | B3 `ParseResult` 语义 | **非缺陷,已文档化** | 逐条推演三个消费者(`MessagePump`/`CompressedCodec`/`UdpSession`)与分隔符协议"帧尾留给下一帧作前导跳过"的设计自洽;已补"尺寸不变量"文档段 | | B4 掩码解码归属 | **不下沉 codec** | 流式体在 `TryParse` 阶段无法解码(掩码需按整帧连续 XOR),下沉会产生半解码状态;改为在 `WebSocketCodec` 明确"不要直接用作 `SessionBase.Protocol`" | | B5 抽 MessageDispatcher | **不做** | 核查确认 UDP 的消息体为内存切片(本就不需要 `DiscardAsync`),两套代码的"漂移"不构成缺陷;抽取会改动 TCP/UDP/UDS 全部交付热路径,收益仅为代码组织 | | B7 事件体系 | **已做** | 删除空别名 `IAsyncEventBus`、修正 `IEventBus` 自相矛盾的注释;`EventHub` 的 5 个 `[Obsolete]` 兼容成员已随 v12 大版本删除(58 个生态仓库核实零真实调用);仅“解码职责拆分”不做 | | B9 `SessionBase` 瘦身 | **不做** | 会连带改 `ISocketSession`/`ITransport`(生态有 Modbus/XCom 实现者);当前流式属性对 UDP 只是"未使用",不产生错误 | | B10 基类引用具体子类 | **不改** | `IStreamSession` 只建模管道,不含流式发送能力;改用接口需给它加发送成员(断实现者)。现有 `is not TcpSession` 守卫行为正确(子类可用、其它类型给出明确异常) | | B12 双 WS 帧循环 | **部分闭环** | 客户端已统一为整帧交付(`RequireFullFrame`);剩余合并为 `WsFrameLoop` 属组织性重构,不做 | | B13/B14 HTTP 异步派发 | **不做** | 属能力级改造(handler 契约升级),需与生态同步;已单列 | > 结论口径:本次以"正确性与兼容性优先、不为代码组织动主流程"为原则(约 90% 覆盖原则)。上表"不做"项均已在本文档留痕,后续如需推进,按 B2 → B5 → B12 → B9 → B7 顺序单项实施、每项独立验证。 ## 附录 A:UdpSession 收敛评估(2026-09-16,仅评估) **现状**:`UdpSession` 不继承 `SessionBase`,独立实现发送(×4)/接收/日志/错误处理;与 `UdpServer` 共享同一 Socket,按远端地址懒建,空包结束会话;`ITransport` 的 `Open/Close` 为桩实现。 **收敛候选**:① 继承 `SessionBase`——基类接收环与每轮拥有句柄模型围绕独占 Socket 设计,UDP 是共享 Socket 按远端分片,直接继承需给基类增加传输抽象层,波及 UdpServer 热路径;② 抽取共享的发送/日志/错误处理助手——范围小,但只消除重复样板,不解决双模型差异。 **结论**:暂不实施。收益(减少重复代码)小于风险(触及 UDP 接收热路径与 2500+ 用例回归面);未来如实施,优先候选 ② 渐进收敛。