docs(net): 监听生命周期根治设计——证据、决策与执行清单
新增 docs/子系统设计/网络Socket监听生命周期设计说明.md(9 节): 原理三层证据——芯片层:LISTEN 与 ESTABLISHED 是同一 TCP 状态字节的互斥 取值(手册 §5.22 L535-545、§5.29 L609「直到连接成功后」),全手册无任何 "连接结束自动恢复监听"条款;且本仓 fun_para=0x08(bit3 SOCKET_CLOSE=1, Trap 18/25 定案)使断开后芯片停在 0x05/0x00,即 B10 看到的"孤儿芯片态" 是本仓配置的合法后果,而非芯片异常。规范层:RFC 1122 §4.2.2.18 明文被动 OPEN MUST NOT affect any previously created connection record,POSIX accept() 原文 socket 不变,lwIP 把监听器所有权写进 tcp_close() 文档—— 本仓需要靠"EOF 不得 close 监听 fd"铁律维持正确性,即架构欠债的凭证。 实现层:EOF 是时序敏感边沿(只在 recv 那一刻 state==CLOSED 才给),导致 重建所有者散成 12 个(栈内 8 + 应用 4)、15 个迁移点、15 个无人负责组合。 关键决定 D1~D7:不启用芯片原生多连接模式(A′ 出局——FTP 改造清单第 4 条 已定案"多连接模式不支持多监听",本产品有 21/8888/7003 三个常驻监听加会 话期动态 PASV,且历史上踩过 Trap 02/11,FUN_PARA 初始化后不可改);采用 "会话结束电平化 + 监听重建单一所有者"的形态 B 深化,不做控制面重写;对 账④保留不撤回(Trap 22 实证事件会丢,周期对账不可删),其副作用由 P1 消除;fun_para 保持 0x08,不回退 Trap 25 的排空契约。 证据附录含 B10 探针日志、A/B 归因数据(基线 5/1/1/5 vs B3 3/7/2/1,均值 3.0 vs 3.25,统计不可区分)、④ 修复后完整回归矩阵、官方 EXAM5/EXAM10 所 有权模型(SDK 行号)、状态机 15 迁移点与关键判据、三服务契约不一致表。 Trap_Records B10 残余改写为指向该文档,并明确记录 ④ 的副作用:抢先 relisten 会把慢消费者的 EOF 永久吞掉,g_client 不清、新客户端数据被旧会 话静默吸收——④ 修好了端口拒连却撑大了另一侧窗口,P1 必须补。 登记行 N-32 已写入 docs/待处理内容.md 工作区,但该文件与并发在途的 N-27 改动混杂,本次不提交,留待其归属方一并入库。
This commit is contained in:
@@ -947,7 +947,7 @@ Trap 22 的周期对账(200ms 节拍 + 400ms 去抖 + 1s 冷却)设计目标
|
||||
| B7 | 低 | `ch395f_test_task.c:1379/1504` | Phase 5 单次写 4093 B 超 1 KB 发送缓冲与 2048 DMA 载荷 → 整块被丢;注释仍写"4096 B = 发送缓冲上限"(2026-09-22 布局解耦前的旧事实)。A6 修后会打 `[ERR]` 而非静默 stall | ⏳ 待修(chunk 改 ≤1024 或分块) |
|
||||
| B8 | 低 | `ch395f_test_task.c:1290-1292` | Phase 4 把 sock6 缓冲重排到块 24-27,与 `net_init` 固定布局中 sock4 的 24-27 **交叠**(§5.45 禁止) | ⏳ 待修 |
|
||||
| B9 | 低 | `ch395f_reuse_bench.c:93`、`net_socket.c:39`、`net_socket.c:262` | bench 用 `get_phy_status() != 0` 判链路(01H=断开也成立,`net_task.c:122` 的 `!= CH395F_PHY_DISCONN` 才对);`NET_PHY_CHECK_INTERVAL_MS` 死宏;无芯片版本门控(§5.16 <0x44 不支持 ALL 版、§5.52 bit3/4 需 ≥0x46,实测 0x4A 无影响) | ⏳ 待修(前两项死代码/卫生) |
|
||||
| B10 | **中** | `net_reconcile_tick` 认领范围 + `handle_disconnect_event` 释放分支(`net_socket.c:3663-3686`) | **孤儿监听 → 端口永久拒连**。断开时释放分支把状态置 `CLOSED` 并注释「留给 `net_recv_locked` 把剩余数据读出来再关,**等待应用重新监听**」——即由应用负责重建;但 `ui_net_sink` 只在 `net_recv` 返 0(EOF)时才清 `g_client`,而 EOF 已被这个事件分支消费掉 → **net 层等应用重建 / 应用等 net 层给 EOF / 对账只裁 ESTABLISHED·LISTENING 直接跳过 / 芯片不会自己回 LISTEN**,四方互等。实测(临时探针):`TEMP orphan sock2 state=0 port=7003 chip=0x05/0x00` 每秒一条持续 12 s+,`:7003 300ms×10` **0/10**、+30 s 仍拒连。与 Trap 22 的关系:Trap 22 的①③两类都要求本层处于 ESTABLISHED/LISTENING,**孤儿态恰好落在两类之外**,所以那套对账全程沉默 | ✅ 已修(2026-10-12):`net_reconcile_tick` 新增**类型④**认领孤儿(`in_use` + `state==CLOSED` + `auto_relisten` + `type==STREAM` + `local_port!=0`,芯片侧不在 LISTEN)→ 复用 `net_relisten_try`(自带"已在重试队列则不重复登记"保护,与 D10 重试队列、Trap 23 沉降隔离兼容)。⚠ **`auto_relisten` 是决定性门**:少了它,"本层 CLOSED + 已绑端口"的**出向连接**(板级 Phase 7 TC701~703 用 `net_connect` 绑本地口)会被误判孤儿并被 relisten 成监听器。**回归**:`:7003 300ms×10` **0/10 → 10/10**(+20 s 存活);`:21` 0ms×50 **50/50**、100ms×50 **50/50**;`:8888` 0ms×20 **20/20**;`ftp_regression` **11/11 ×2**;Trap 23 RST **5/5**、FIN **5/5**;`@test` PASS(600 ms、回读无差异);`Code` 197008→197084。⚠ **残余(未根治)**:生产者仍在——释放分支依旧把状态停在 `CLOSED` 等应用重建,④是**兜底**(实测救援后端口 1 s 内恢复,日志 `reconcile: orphan listener … -> relisten` 可见);根治要在释放分支对 `auto_relisten` 直接重监听,但那会破坏「让 `net_recv_locked` 读干剩余数据」的 Trap 25 closed-with-data 契约,须单列评估 |
|
||||
| B10 | **中** | `net_reconcile_tick` 认领范围 + `handle_disconnect_event` 释放分支(`net_socket.c:3663-3686`) | **孤儿监听 → 端口永久拒连**。断开时释放分支把状态置 `CLOSED` 并注释「留给 `net_recv_locked` 把剩余数据读出来再关,**等待应用重新监听**」——即由应用负责重建;但 `ui_net_sink` 只在 `net_recv` 返 0(EOF)时才清 `g_client`,而 EOF 已被这个事件分支消费掉 → **net 层等应用重建 / 应用等 net 层给 EOF / 对账只裁 ESTABLISHED·LISTENING 直接跳过 / 芯片不会自己回 LISTEN**,四方互等。实测(临时探针):`TEMP orphan sock2 state=0 port=7003 chip=0x05/0x00` 每秒一条持续 12 s+,`:7003 300ms×10` **0/10**、+30 s 仍拒连。与 Trap 22 的关系:Trap 22 的①③两类都要求本层处于 ESTABLISHED/LISTENING,**孤儿态恰好落在两类之外**,所以那套对账全程沉默 | ✅ 已修(2026-10-12):`net_reconcile_tick` 新增**类型④**认领孤儿(`in_use` + `state==CLOSED` + `auto_relisten` + `type==STREAM` + `local_port!=0`,芯片侧不在 LISTEN)→ 复用 `net_relisten_try`(自带"已在重试队列则不重复登记"保护,与 D10 重试队列、Trap 23 沉降隔离兼容)。⚠ **`auto_relisten` 是决定性门**:少了它,"本层 CLOSED + 已绑端口"的**出向连接**(板级 Phase 7 TC701~703 用 `net_connect` 绑本地口)会被误判孤儿并被 relisten 成监听器。**回归**:`:7003 300ms×10` **0/10 → 10/10**(+20 s 存活);`:21` 0ms×50 **50/50**、100ms×50 **50/50**;`:8888` 0ms×20 **20/20**;`ftp_regression` **11/11 ×2**;Trap 23 RST **5/5**、FIN **5/5**;`@test` PASS(600 ms、回读无差异);`Code` 197008→197084。⚠ **残余(未根治,已立项根治)**:生产者仍在——释放分支依旧把状态停在 `CLOSED` 等应用重建,④是**兜底**(实测救援后端口 1 s 内恢复,日志 `reconcile: orphan listener … -> relisten` 可见)。⚠ **④ 有副作用**:`net_recv` 的 EOF 是**边沿**(只在 recv 那一刻 `state==CLOSED` 才给 0,`:1880-1888`;已被别处 relisten 回 LISTENING 则恒 `WOULDBLOCK`,`:1890`)→ ④ 抢先 relisten 会把慢消费者的 EOF 永久吞掉,`g_client` 不清、新客户端数据被旧会话静默吸收。**原理与分阶段根治方案 → `docs/子系统设计/网络Socket监听生命周期设计说明.md`**(含:芯片层为何永不自动回 LISTEN、本仓 `fun_para=0x08` 使 `0x05/0x00` 成为合法常驻态、RFC 1122 §4.2.2.18 与 POSIX accept 的规范冲突、12 个重建所有者与 U1~U15 无人负责组合、以及"芯片原生多连接模式(A′)为何对本产品不可用"的决定性证据) |
|
||||
|
||||
### 文档侧待修清单(本轮只改了最要紧的几处,其余登记在此)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user