# dlt860_publish **Repository Path**: kangsong/dlt860_publish ## Basic Information - **Project Name**: dlt860_publish - **Description**: No description available - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2026-10-08 - **Last Updated**: 2026-10-09 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # 国网自主化通信协议 DL/T 860 作品展 > 一套面向电力自动化的自主化通信协议(DLT860 / CMS)完整解决方案:从"字节流传输"到"报文编解码"再到"IED 设备建模",并以一套可直接上手的 Qt 客户端工具,把协议能力变成看得见、点得动的生产力。 --- ## 一、作品总览:一条打通的完整链路 本作品展围绕 **DL/T 860(CMS)** 这一国网自主化通信协议展开,以"**职责单一、依赖单向、应用粘合**"为设计主线,把"通信、协议、建模、应用"四个关注点彻底拆开,再组装成一条 **字节流 ⇄ 报文 ⇄ 内存模型 ⇄ 业务界面** 的完整数据通路。 | 作品 | 扮演的角色 | 一句话说明 | | --- | --- | --- | | **uv_net** | 通信管道 | 协议无关的异步网络库,只认识字节,不认识协议 | | **dlt860_codec** | 协议翻译官 | BASIC-PER 编解码库,57 个标准服务全量覆盖,零外部依赖 | | **dlt860_model** | 数字档案与操作台 | IED 内存模型库,把设备结构装进电脑,可查可控 | | **gui_dlt860_client** | 客户端工具 | Qt5 客户端,7 大业务页全部接通真实服务 | ### 工程量化指标 | 指标 | 数值 | 说明 | | --- | --- | --- | | 服务覆盖 | **57 个 SC** | 关联 / 目录 / 读写 / 数据集 / 控制块 / 遥控 / 定值组 / 报告 / 日志 / 文件 / RPC 全量 | | 编解码依赖 | **0 个第三方库** | 纯 C99,仅 libc + `-lm`,无 IO 无 socket | | 传输加密 | **双模式 TLS** | 标准 TLS + 国密 GMTLS,握手失败绝不降级明文 | | 建模来源 | **CID / ICD / SCD** | 单文件支持 300+ 装置的分步导入 | | 网络抽象 | **4 套 Manager** | TCP/UDP × 客户端/服务端 | | 客户端业务页 | **7 个** | 全部接通真实服务,非 UI 占位 | --- ## 二、分层架构:可拆、可换、可复用 整套方案遵循一条主线:**把"通信""协议""建模"三个关注点彻底拆开,各自只做一件事,再由应用层把它们组装起来。** ``` ┌──────────────────────────────────────────────┐ │ 应用层 (你的程序) │ │ 串联收发、处理业务语义、协调各模块 │ └───────┬──────────────┬───────────────┬────────┘ │ │ │ ┌───────▼──────┐ ┌─────▼────────┐ ┌────▼─────────┐ │ uv_net │ │ dlt860_codec │ │ dlt860_model │ │ 字节流收发 │ │ 报文编解码 │ │ SCL 数据建模 │ │ (认识字节) │ │ (认识报文语义) │ │ (认识设备结构) │ └──────────────┘ └──────┬───────┘ └────┬─────────┘ ✗ 无依赖 │ 仅复用公共头类型 │ ◀──────────────┘ ``` ### 2.1 三条核心原则 | 原则 | 含义 | 工程收益 | | --- | --- | --- | | **职责单一** | `uv_net` 不认识协议,`dlt860_codec` 不碰 socket,`dlt860_model` 不碰网络 | 模块边界清晰,编译依赖最简,问题定位快 | | **依赖单向** | 仅 `dlt860_model → dlt860_codec` 复用**公共头类型**(不依赖实现);`uv_net` 与两者零依赖 | 换网络库不用动协议,换协议不用动网络 | | **应用层组装** | 三个库之间不直接互相调用,由应用层按需把它们的输出接到对方的输入上 | 集成方式统一,易于单元测试与移植 | ### 2.2 为什么这样分层 - **网络层只管搬运**:把一段字节安全送到对端,或把收到的字节交出来,对内容一无所知——因此天然可换(换成别的 IO 框架不影响协议)。 - **编解码层只管翻译**:把字节与结构化报文互相转换,不碰任何 socket——因此是纯函数式的、天然可测的模块,也能在没有网络的环境里单独使用。 - **模型层只管描述设备**:把装置的结构与数据装进内存,不碰网络、不碰字节——因此可以给任意上层工具复用。 三层互不侵入,任一模块都能被**单独替换或单独复用**。这正是"灵活"的来源:需要哪个用哪个,需要全套就整套上。 ### 2.3 模块间的静态依赖 | 从 | 到 | 依赖内容 | | --- | --- | --- | | `dlt860_model` | `dlt860_codec` | **仅公共头类型**(`dlt860_data_t` / `dlt860_datadef_t` / `dlt860_objref_t` / `dlt860_fc_t`),不依赖实现 | | `dlt860_codec` | `uv_net` | **无依赖** | | `uv_net` | 其它两者 | **无依赖** | | 应用层 | 三者 | 全部依赖,并负责串联 | > 这种"零环依赖"的结构,使得每个库都能独立编译、独立测试、独立发布,集成时也不会出现版本纠缠。 --- ## 三、作品一:uv_net —— 让数据传递稳如磐石 > 协议无关的异步网络库 · C++11 动态库 它只负责"把一段字节安全送到对端"和"把收到的字节交出来",**对字节内容一无所知**。 ### 3.1 核心技术:多线程事件循环 + 命令队列 这是 uv_net 最关键的工程实现。每个 IO 线程拥有**独立的 `uv_loop`**,跨线程调用不直接操作 socket,而是走"**拷贝 → 投递 → loop 线程执行**"三段式: ``` 业务线程 IO 线程 (持有 uv_loop) │ │ │ sendData(id, data, len) │ │ ① 数据拷贝进 Command 对象 │ │ ② uv_async_send() 唤醒 ────────────▶│ │ │ ③ uv_async 回调触发 │ │ ④ 从命令队列取 Command │ │ ⑤ 在本 loop 内执行 uv_write │◀──────── callbackSendFailed (可选) ─│ ``` **设计价值**: - **消除锁竞争**:socket 只被其所属 loop 线程操作,无需为每个 socket 加锁。 - **避免跨线程句柄误用**:libuv 句柄非线程安全,命令队列把"操作发起者"与"对象持有者"彻底分离。 ### 3.2 线程绑定策略 | 角色 | 绑定方式 | 说明 | | --- | --- | --- | | 客户端连接 | 按 `connectId` 取模分派到 IO 线程 | 单连接的全部事件固定在一个 loop | | 服务端 server | 整体绑定单个线程(`m_preferThreadIndex`,`-1`=轮询) | 单监听器的 accept + 全部连接 IO 在同一 loop | > 这一绑定关系直接决定并发规划:客户端是"连接分散到多线程",服务端是"每个监听器独占一个线程"。线程数被收敛到 `[1, 16]`。 ### 3.3 关键配置项(精细到 socket 层) | 配置 | 默认值 | 含义 | | --- | --- | --- | | `m_reconnectEnable` | `true` | 自动重连 | | `m_useExponentialBackoff` | `true` | 指数退避重连 | | `m_reconnectBaseDelay` / `m_reconnectMaxDelay` | `500` / `30000` ms | 退避区间 | | `m_keepaliveIdle` / `m_keepaliveInterval` | `5` / `2` s | TCP KeepAlive 探测 | | `m_noDelayEnable` | `true` | 禁用 Nagle(TCP_NODELAY),降低小包延迟 | | `m_sendHighWatermark` | `0` | 单连接待发字节上限,超限丢弃并触发 `callbackSendFailed(-3)` | | `m_connectionIdleTimeoutMs` | `0` | 连接空闲超时自动断开 | ### 3.4 生命周期与竞态防护 - **自引用保活**:连接/会话对象通过自引用计数保证在 libuv 句柄 `close` 回调执行前不被析构;`stop`/析构竞态用 `m_keepAlive` + `m_pendingClose` 计数保护,有 `test_stop_dtor_race` 专项测试覆盖。 - **句柄单调递增不复用**:`connectId` / `serverId`+`connId` 可直接作为业务侧会话键,避免 ABA 问题。 ### 3.5 发送语义(最容易被误用的点) | 返回值 | 真实含义 | | --- | --- | | `false` | **确定性不可达**——ID 不存在 / 参数非法 / 管理器未 start,数据绝不会发出 | | `true` | **仅表示命令已成功入队**,不代表已发出、更不代表对端收到 | 真正的发送结果只能通过 `callbackSendFailed` 获知(`-1` 未连接、`-2` 写同步失败、`-3` 背压丢弃)。**绝不能用返回值推断业务成功。** ### 3.6 国密传输 `TlsContext` 封装 `SSL_CTX`(每连接独立创建、可跨重连复用),`TlsSession` 封装 `SSL` + BIO 驱动握手/加解密。TCP 连接在 `m_tlsMode != eDisabled` 时于 `onConnect` 后启动握手,**对业务完全透明**(握手成功才回调 `connected`)。GM 模式下填入国密套件(如 `0xE102`),**握手失败绝不降级为明文**。 --- ## 四、作品二:dlt860_codec —— 绝不"答非所问"的协议翻译官 > BASIC-PER 编解码库 · 纯 C99 · 零外部依赖 把"结构化数据"与"协议报文字节"互相转换,并处理 TCP 流上的**粘包切分与分帧重组**。它是纯计算模块,**不碰任何 socket**。 ### 4.1 六层结构 ``` core → types → frame → service → ctx → util 位流原语 递归CHOICE 帧头+粘包切分 信封+分发表 无IO状态机 名称/字符串表 ``` ### 4.2 核心技术之一:位流编解码(bit-level PER) 这是编解码层的根基。协议采用 **BASIC-PER** 风格,字段**不按字节对齐**,一个字段可能只占几位、跨越字节边界: | 技术点 | 实现 | | --- | --- | | **位流读写器** | `dlt860_bw_t` / `dlt860_br_t`,MSB-first,支持任意位宽读写(如 64 位字段跨非对齐字节边界) | | **CHOICE 索引宽度** | 按分支数动态取位:24 个分支 = `⌈log2(24)⌉ = 5` 位 | | **长度决定量** | `dlt860_perlen_encode/decode`:`≤127` 用 1 字节短格式 `0nnnnnnn`,否则 2 字节 | | **粘性错误** | 一旦某次读写失败,后续操作直接短路返回同一错误,**无需每步检查**,大幅简化调用方判错 | | **空跑计长** | `buf == NULL` 时只累计位数不写字节,用于**预估算缓冲区容量** | ```c /* 双遍编码:先空跑算长度,再实写并回填帧长 FL */ int dlt860_pdu_build_size(/* 空跑编码,返回所需字节数 */); int dlt860_pdu_build(uint8_t *out, size_t cap, size_t *out_len, uint16_t req_id, uint8_t sc, bool err, dlt860_pdu_enc_fn enc, const void *params); ``` ### 4.3 核心技术之二:OPTIONAL presence bitmap(preamble) SEQUENCE 中的 OPTIONAL 字段,其"是否存在"由**逐字段 1 位**的位图(preamble)表达,且**必须置于该 SEQUENCE 所有字段的最前面**(含必选字段之前)。这是与真实服务端 wire 格式严格对齐的关键: ``` 关联响应 example: 字节 04 = (isAuth << 7) | (len & 0x7f) ↑ 最高位是 preamble(是否带认证) ↑ 低 7 位是非对齐长度 两者拼在同一个字节里 —— 这正是"位级编码"的直接体现 ``` > 位数 = OPTIONAL 字段个数;`DEFAULT TRUE` 的布尔(如 `moreFollows`)也按"是否被显式编码"占 1 位 preamble。 ### 4.4 核心技术之三:帧层——粘包切分与分帧重组 TCP 是字节流,报文会被任意切分或粘连。这两个机制彻底解决该问题: | 机制 | 结构/常量 | 作用 | | --- | --- | --- | | **粘包切分** `deframe` | `{hdr[4]; have, need; body*; body_cap, body_have; in_frame}` | 按帧长 FL 增量切出一个完整帧(FL = ASDU 长度,不含 4 字节 APCH) | | **分帧重组** `reasm` | `DLT860_MAX_REASM_SLOTS=16`,`DLT860_MAX_REASM_SIZE=16MB` | 按 ReqID 分 16 槽,把跨多个 APDU 的同一请求重组回完整 ASDU | ```c /* 收流一条龙:feed → deframe → reasm → on_pdu */ int dlt860_ctx_feed(dlt860_ctx_t*, const uint8_t*, size_t); ``` ### 4.5 核心技术之四:服务分发表(SC 升序 + 二分查找) ```c typedef struct { uint8_t sc; uint16_t flags; } dlt860_dispatch_entry_t; /* 表必须严格按 SC 升序排列,dlt860_dispatch_flags() 用二分查找 */ ``` **这是一处"看起来能跑、实际错得很隐蔽"的设计约束**:向表尾追加新服务而不是插入到正确的升序位置,会导致二分查找区间错乱,大批服务静默失效(返回错误的 flags)。当前全表 57 项严格升序。 ### 4.6 核心技术之五:未决请求表(ReqID 自动分配与匹配) ```c uint16_t dlt860_ctx_alloc_reqid(dlt860_ctx_t*); /* 从 1 起递增 */ void dlt860_ctx_register_pending(dlt860_ctx_t*, uint16_t, uint8_t); bool dlt860_ctx_lookup_pending(dlt860_ctx_t*, uint16_t, uint8_t*); ``` - `pending[256]`:登记在途请求(ReqID → SC 映射),收到响应时按 ReqID 反查服务码。 - `ReqID = 0` 保留给**主动上送**(如 Report)。 - 表满时采用"**覆盖最旧**"策略(软性丢弃),建议业务侧控制在途并发数。 - **TCP 重建后必须 `ctx_clear()` + `ctx_init()` 复位**:`ctx_clear()` 会整体清零(含回调指针),不重新 init 会导致回调为空、ReqID 不从 1 起。 ### 4.7 三种使用层次 | 层次 | 入口 | 适用场景 | | --- | --- | --- | | ① 裸编解码 | `dlt860_data_encode/decode`、`srv_xxx_req_pack/unpack` | 自行管理帧与上下文 | | ② 帧级 pack/unpack | `dlt860_pdu_build/parse` + `srv_xxx_*` | 自行管理连接,使用 PDU 信封 | | **③ 上下文状态机** | `dlt860_ctx_*` | **推荐**,一把梭解决粘包 / 重组 / ReqID | ### 4.8 类型安全设计 - 每个服务有**独立强类型** `xxx_req_t / xxx_resp_t`,拒绝用巨型 union 汇聚。 - `dlt860_data_t` 是递归 CHOICE(各类基本类型 + 结构 + 数组),带 `DLT860_MAX_RECURSE_DEPTH` 深度防护(超深返回 `DLT860_ERR_BUF_UNDERFLOW`)。 - 否定响应区分两条路径:`ServiceError`(统一错误码)与结构化错误体(服务特有 SEQUENCE,走 `*_raw` 变体)。 --- ## 五、作品三:dlt860_model —— 把设备"搬进"电脑的数字档案 > IED 内存模型库 · C++11 动态库 · 基于 pugixml 把一台装置(或整站)的**静态结构**与**运行态数据**,在内存中建立成完整的对象树。 ### 5.1 对象树模型 ``` IedModel → LogicalDevice → LogicalNode → DataObject → DataAttribute └─ sub_do (SDO 递归) DataAttribute └─ sub_da (SDA 递归) ``` 旁挂 `DataSet`、`ControlBlock`(`ReportCB / LogCB / SGCB / GoCB / MSVCB`),每个节点用 `reference()` 逐级拼出标准 ObjectReference。数组元素经 `elems` 展开。 ### 5.2 核心技术之一:与编解码层共用类型,实现"零转换" 这是模型层与编解码层的高效衔接关键:`BType` 就是 `dlt860_data_kind_t` 的别名,`dlt860_fc_t` 枚举值两边完全一致。模型里读出的 `dlt860_data_t` 可以**几乎零转换**地交给编解码层打包——这正是服务端能高效回包的底层原因。 ### 5.3 核心技术之二:SCL 递归导入与成环防护 SCL 的 `DataTypeTemplates` 是**类型引用图**(`LNodeType → DOType → DAType` 多层递归引用),导入过程用带深度上限的递归展开: ```cpp if (depth > 64) { scl_errlog_push(log, SCL_ERR_SEMANTIC, SCL_REASON_CIRCULAR_REF, SCL_SEV_WARNING, 0, "DOType", "id", dotype_id, "类型递归超深,疑似成环"); return nullptr; } ``` - **成环防护**:`depth > 64` 判定为引用成环,记录 `SCL_REASON_CIRCULAR_REF` 而非死循环崩溃。 - **count 驱动的数组展开**:`` / `` 自动展开为 `is_array` / `array_count` / `elems[]`。 - **模板默认值**:`/` 内嵌的 `` 直接转为默认值。 ### 5.4 核心技术之三:大文件分步导入 ```cpp /* 超大 SCL(数百台装置)不要一次性导入,改用"load 一次 + 逐 IED 构建" */ SclDoc* d = dlt860_scl_load(path); /* 解析一次,DOM 常驻 */ for (auto& ied : names) dlt860_model_build_ied(d, repo, ied.c_str()); /* 反复构建,复用同一 DOM */ dlt860_scl_unload(d); /* 及时释放,峰值内存不随文件数增长 */ /* 仅需 A/B 网 IP 摘要时,用极快路径(不建模型树、不解析 DataTypeTemplates) */ dlt860_scl_scan_ied_net(path, &addrs); /* 150MB/300IED 场景友好 */ ``` ### 5.5 核心技术之四:四维错误码 + 行号反查 导入错误不是简单返回失败,而是按 **错误类别 × 错误原因 × 严重度 × 位置** 四维建模,用 `scl_errlog_t` 收集器累积:warning 继续解析、fatal 中止;配合 `offset_to_line()` 把 pugixml 的字节偏移反查为**行号**,定位到具体 ``。 ```cpp /* 错误原因枚举(部分) */ SCL_REASON_UNRESOLVED_REF /* 引用未解析 */ SCL_REASON_TYPE_MISMATCH /* 类型不匹配 */ SCL_REASON_IX_RANGE /* ix 越界 */ SCL_REASON_CIRCULAR_REF /* 引用成环 */ SCL_REASON_UNSUPPORTED /* 暂不支持 */ ``` ### 5.6 双入口,共用一条构造路径 SCL 导入(`scl_load` → `model_build_ied`,经中间表示 `ModelDescription/*Desc`)与编程式 `add_*`,**共用同一套节点构造路径**——保证两种建模方式产出的模型结构完全一致。 --- ## 六、作品四:gui_dlt860_client —— 可直接上手的客户端工具 > Qt5 Widgets 可执行程序 · 7 大业务页面全部接通真实服务 把协议能力变成看得见、点得动的图形工具,是三大库能力的最佳落地示范。 ### 6.1 七大业务页面 | 页面 | 主要功能 | | --- | --- | | 数据对象 | 浏览 LD / LN / DO / DA 对象树,查看与设置实时值 | | 数据集 | 查看数据集成员(FCDA),核对引用与功能约束 | | 控制块 | 查看 / 设置 BRCB / URCB / GoCB / MSVCB 等控制块参数 | | 遥控 | 下发控制命令,处理选择与执行流程 | | 保护定值 | 读取与下发定值组,按类型解析设置值 | | 日志查询 | 查询装置日志与事件记录 | | 文件操作 | 浏览与传输装置文件 | ### 6.2 核心技术之一:A/B 双网择优回退 ``` ┌────────────┐ │ IedConnection │ └───┬────────┬───┘ A 通道 │ │ B 通道 (独立常连) (独立常连) ▼ ▼ 发送时:优先 A → A 不可用则回退 B 重连:每网口独立 15s 定时器自管 ``` 两网**独立常连**,发送时择优回退,任一网口断开不影响另一网口——这完全契合电力现场 A/B 双网冗余的部署要求。 ### 6.3 核心技术之二:回调线程切换(跨线程安全) uv_net 回调发生在 **libuv IO 线程**,而 Qt 的 UI 操作必须在 **GUI 主线程**。客户端用 `QMetaObject::invokeMethod(..., Qt::QueuedConnection)` 把事件投递回主线程: ``` IO 线程: callbackReceive(id, data, len) │ ① 数据拷贝(data 生命周期仅限本次回调) │ ② QMetaObject::invokeMethod(Qt::QueuedConnection) ▼ GUI 线程: ctx_feed → on_pdu → respack 解包 → 写模型 → 刷新界面 ``` ### 6.4 通信链路总览 ``` 收: 网络回调 → ctx_feed → deframe 切包 → reasm 重组 → on_pdu 分派 → srv_xxx_resp_unpack → 回写 ModelRepository → 界面刷新 发: 取模型数据 → srv_xxx_req_pack → ctx_send → on_output → sendData ``` ### 6.5 其他工程细节 - **RCB 自动使能**:连接建立后自动完成报告控制块使能,并解包上送报告刷新界面。 - **在线建模**:既支持 SCL 文件导入建模,也支持连上装置后在线逐层拉取模型。 - **配置持久化**:主窗口几何与连接配置以 JSON 落盘(`ClientConfigIO`),下次启动即恢复。 - **模型指针生命周期**:视图持有的模型节点是**裸指针(非拥有)**,模型重置时通过 `sigModelReset` / `sigIedRemoved` 信号先关闭窗口,避免悬空访问。 --- ## 七、跨模块关键约定(技术精华) 这套作品能稳定协作,靠的是一系列**严格的跨模块约定**。违反这些约定,多数会表现为"能编译、能跑,但结果静默错误": | # | 约定 | 违反后果 | | --- | --- | --- | | 1 | BASIC-PER presence bitmap 置于 SEQUENCE **最前面** | 对端解析错位 | | 2 | 服务分发表**按 SC 严格升序**(二分查找) | 追加表尾会导致大批服务错路由 | | 3 | `dlt860_codec` **不得引入 socket / IO** | 破坏分层,编解码无法在无网络场景复用 | | 4 | TCP 重建后必须 `ctx_clear()` + `ctx_init()` | 回调为空、ReqID 不从 1 起 | | 5 | uv_net 回调的 `data` **生命周期仅限本次回调** | 跨回调保存会读到野内存 | | 6 | `sendData` 返回 `true` **不代表送达** | 误判业务成功 | | 7 | 模型查询返回**裸指针(非拥有)** | 模型重建后上层缓存指针悬空 | --- ## 八、组合价值:一次投入,三倍省心 ### 用"寄快递"来理解四者的协作 | 角色 | 对应作品 | 职责 | | --- | --- | --- | | 快递网络 | **uv_net** | 无论刮风下雨,都负责把包裹安全送到对方手中 | | 打包 / 拆包规范 | **dlt860_codec** | 确保寄出的东西对方能原样看懂,不漏件、不串件 | | 收发台账 | **dlt860_model** | 记录每台设备的全部信息,随时查阅与更新 | | 操作台 | **gui_dlt860_client** | 把一切能力变成可见、可点、可下发的界面 | ### 一次完整的数据旅程 ``` ① 从档案取数据 → ② 翻译官打包成标准报文 → ③ 快递网络送达对方 → ④ 回信:网络收下 → 拆包 → 写回档案 ``` ### 单独看 vs 组合看 | 单独看 | 组合看 | | --- | --- | | 每个作品都能独立复用,投资灵活 | 一次性覆盖"传输 — 翻译 — 建模 — 应用"全链路 | | 作品之间零冲突、接口天然衔接 | 集成成本低,落地周期短 | | 能力经过真实项目验证 | 客户端工具已基于它们成功落地,不是纸上谈兵 | | 支持国密安全能力 | 一套方案同时满足功能与合规双重需求 | ### 典型适用场景 - **装置开发与测试**:电力自动化装置 / 终端的联调与功能验证。 - **协议一致性测试**:装置模拟器、协议一致性测试工具的开发底座。 - **监控与运维软件**:监控、配置、运维类软件的产品化开发。 - **国产化项目**:需要支持国密安全传输的自主可控项目。 - **大型系统集成**:数百台装置同时建模的场景(支持分步导入)。 --- ## 九、技术亮点速览 | 模块 | 技术亮点 | | --- | --- | | **uv_net** | 多线程事件循环 + `uv_async` 命令队列;自引用保活防 stop/dtor 竞态;句柄单调递增不复用;国密 GMTLS 对业务透明 | | **dlt860_codec** | 位级 PER 编解码(MSB-first + 粘性错误 + 空跑计长);preamble 位图与 CHOICE 索引位宽;粘包切分 + 16 槽分帧重组;SC 升序二分查找分发表;ReqID 自动分配与未决表匹配 | | **dlt860_model** | 与编解码层共用类型实现零转换;类型引用图递归 + `depth>64` 成环防护;四维错误码 + 行号反查;分步导入大文件 | | **gui_dlt860_client** | A/B 双网择优回退 + 独立重连;`QueuedConnection` 跨线程回调;7 大业务页全接通 | --- ## 结语 **uv_net 让您连得上,dlt860_codec 让您说得清,dlt860_model 让您看得见。** 四个作品各有所长、又能无缝配合,共同支撑起一套自主可控的 DL/T 860 协议栈与配套工具,帮您用更少的重复劳动,做出更稳定、更专业的产品。 > **一次投入,三倍省心** —— 把通信、协议与建模的难题交给成熟组件,把宝贵的人力留给真正的业务创新。 --- *术语统一采用 DLT860 / CMS。*