fix(网络): 主动拆会话登记即返——drop 路径不再占用 netTask(登记簿 N-17 收口)

道F 批 2 / task-17。定位 + 单点收口,不开 net 层跨上下文大口子。

【定位(链路,全部代码可复核)】
探针挂起 30s → time_sync.c:149 预算耗尽 → :187 net_drop_conn()。NET_MSG_
DROP_CONN 处理器(net_drop_conn_locked)内同步跑 net_sock_reset_sync
(QUARANTINE)(2ms 节奏、400ms 底/600ms 顶,自家注释原记「等待期 netTask
有界占用 ~400-600ms」):netTask 的 1ms 主循环冻结在同一迭代 → NET 位
停摆;串行总线整窗停摆 → UI 推流/FTP/104 在途消息回执顺延;对时调用方
睡在 net_wait_result 等回执期间无分片心跳 → 五位同窗缺席 → 连续 8 个
100ms 抽样停喂 → 声明 [WD] task stall(V5 时代 req=0x37、快照只剩 bit0,
即日志 mask=0x00000001)。被动断连/EOF 走 net_listener_tick 异步沉降机
(D10 条令)故纯 FTP 负载 0 stall——只有主动 drop 留在同步原语里。

【修复】监听型 fd 的芯片拆除改为 net_listener_settle(QUARANTINE) +
net_listener_request(REQ_DROP) 登记即返,拆链/排渣/等 CLOSED/重建全部
交 net_listener_tick 30ms 节奏——与被动释放同一台机器(E16 台架实证该
自建序列 RST 10/10、FIN 5/5)。非监听 client fd 无监听可保,同步形态
原样保留(全仓零生产调用者)。返回值语义显式改为「拆除与重建已登记」
(net_socket.h 注释按 lead 要求写明,防未来调用方按旧语义写)。
APP_ASSERT(S12 试点)分派门与断言位置未动,登记时序下仍成立。

【评估否决留档(lead 要求论证入文档)】「缩短重建重试 5×2s」不采:
该退避在 time_sync_open_listener() bind/listen 失败路径、已被
time_sync_delay_fed() 分片喂保护、不在缺口链上;缩短反撞 TRAP-NET-09
沉降窗。全文见 docs/网络/网络自愈架构设计.md §4.6(已改写)。

【竞态与信源核对】① 主路径置 CLOSED 后迟到的 DISCONNECT/TIMEOUT 被
net_events 状态门拦截(只认活会话态),不会把刚登记的 QUARANTINE 降级;
② 零新增读清点——全局寄存器唯一读者仍 net_poll,隔离窗两处本 Socket
读清是 net_listener_tick 原位,§4.10 三条准入判据不触发;③ E13 物理
边界(对端不配合 FIN_WAIT_2 长尾)逐字不变,只移动等待发生的位置。

【测试】net_socket 主机套件 457/457:TC-NETSOCK-240f/321b/321b2/460e
重锚到登记式(settle+REQ_DROP、rst 机零启动、tick 预算 ≤20、无 [ERR]),
新增 321g/h/i + 460f 钉住 client fd 旧同步形态。全量 --all-files 40 绿。

【体积增量(vs scripts/ram_baseline.tsv 2026-10-25 行)】
ER_IROM1 237328→237344(+16 B);RW_IRAM1 75792(+0);ZI 0。
@build 0 错误 0 警告(Code=215948 RO=21396 RW=1232 ZI=131984)。

gate: only mem-budget/mem-numbers pending lead ledger backfill
test-coverage 本条**绿**(已覆盖行净增,未动用裁决③的覆盖率例外——
旧同步路径行经 client fd 新用例继续被覆盖,净差非负)。其余含
id-check/doc-links/全部主机单测绿。仅 mem-numbers/mem-budget 两红 =
台账 +16B 漂移待回填(lead 单写者禁区)。

【越界申报】① test/host/net_socket/{ns_s3_msg,ns_s4_state,ns_s5_io}.c
(批准③同类:只动本任务相关用例,未碰他人行);② docs/网络/
网络自愈架构设计.md §4.6 改写(lead 本任务指令明示)。登记簿 N-17
销项与 README 波次行归 lead;docs/内存管理 数字未碰(禁区)。

台架:V5 复跑判据(e02_probe + FTP ≥30min 零 stall / 零复位)属网络
对端类——待 lead 排窗,步骤清单随 done 消息发出。
This commit is contained in:
2026-10-25 10:08:46 +08:00
parent 042e85820c
commit a3c6e89378
6 changed files with 108 additions and 26 deletions
+36 -8
View File
@@ -422,17 +422,45 @@ CLOSED → 由形态④ 接手。关键在两条快路径的判据(`net_pendin
必须 `net_select` 超时或 `net_recv_to` 显式预算。
- 上层 32 轮盲收(`ui_net_sink` / `iec104_serv`)保留现状(E6 裁决,§4.8)。
### 4.6 `net_drop_conn`——应用主动拆会话保监听(E-02 收口)
### 4.6 `net_drop_conn`——应用主动拆会话保监听(E-02 收口;N-17 异步收口 2026-10-25)
- 语义:`net_pending_settle_close` 先结束挂起 recv(回传结果 + 唤醒调用方)→
`net_sock_reset_sync(QUARANTINE)` → 本层收口 CLOSED(不清 fd)→ `auto_relisten` 即时登记
重建请求(`net_listener_tick` 执行;失败交 D10 + 形态④)。
- 语义(**返回值 = 拆除与重建已登记**,不代表芯片已拆完):`net_pending_settle_close`
先结束挂起 recv(回传结果 + 唤醒调用方)→ 监听型(`auto_relisten`)fd:
`net_listener_settle(QUARANTINE)` + `net_listener_request(REQ_DROP)` 登记即返,
芯片拆除(FIN 关闭 + 排渣 + 排空事件 + 等 byte0=00H)与重建由 `net_listener_tick`
按 30ms 节奏执行(与被动超时/断连释放同一台机器),失败交 D10 + 形态④;
非监听 client fd 无监听可保,仍同步 `net_sock_reset_sync`(600ms 封顶)。
端口恢复窗 ~0.4~1s,与被动断连恢复窗(E1 发现 A)同型。
- **为什么监听型不得同步等待(N-17 定位,论证随结论一并留档)**:旧形态在
`NET_MSG_DROP_CONN` 处理器内同步跑 `net_sock_reset_sync(QUARANTINE)`(2ms 节奏、
400ms 底/600ms 顶,自家注释原记「等待期 netTask 有界占用 ~400-600ms」),netTask
的 1ms 主循环冻结在同一迭代内:NET 位心跳停摆 + 串行总线整窗停摆(UI 推流/FTP/
104 在途消息回执顺延、调用方在其分片/无限等待中不见回执)+ 对时调用方自己睡在
`net_wait_result` 等回执、期间无分片心跳——五位同窗缺席 → 连续 8 个 100ms 抽样
停喂 → 声明 `[WD] task stall`(V5 时代 req=0x37,缺席位恰为 NET/FTP/UI/对时,
快照只剩 bit0,即日志中的 `mask=0x00000001`),缺口 800ms~1s,距 IWDG 最坏超时
1701ms 余量仅 ~0.7s;同场隔离负载(纯 FTP 120s)0 次——因为被动拆链走的本就是
异步沉降机(D10「重建必须非阻塞」条令),只有主动 drop 一条路径留在同步原语里。
- **评估否决的方向——「缩短重建重试(5×2s)」**:该退避链在
`time_sync_open_listener()` 的 bind/listen 失败路径,全程走
`time_sync_delay_fed()` ≤50ms 分片喂心跳,且**不在 drop→拆链→重监听的心跳缺口
链上**;缩短它不消除本缺口,反而加大对芯片沉降窗的撞车风险(TRAP-NET-09:关闭
后需沉降才能重开),故不采。
- **竞态与信源核对**:① 主路径置 CLOSED 后迟到的 DISCONNECT/TIMEOUT 事件被
`net_events` 的状态门拦截(只认活会话态),不会把刚登记的 QUARANTINE 降级为
GRACEFUL;② 零新增读清点——隔离窗内两处本 Socket 读清仍在 `net_listener_tick`
原位置(§4.10.2),全局寄存器唯一读者仍是 `net_poll`;③ 生产调用者全仓仅
`time_sync.c`(不消费返回值,accept 轮询天然容忍 WOULDBLOCK 窗)。
- **幂等**(非 ESTABLISHED/CONNECTING 直接返 0);**EOF 路径不得调**
(`auto_relisten` 已接管,再调属重复拆)。
- 芯片物理边界(E-02 台架):`close` **无 RST 语义**——对端配合(收到 FIN 后其内核
close):`TIME_WAIT` ~150ms → 形态④ relisten(恢复全程 ~500ms);对端内核存活但
不 close:芯片停 `FIN_WAIT_2` 长尾,**监听恢复受限于对端 close**,兜底 = 芯片
TIMEOUT/KeepAlive 拆僵尸 30~90s(E13)——不是应用可加速的路径。
- 芯片物理边界(E-02 台架,异步收口逐字不变——只移动「等待发生在哪」):
`close` **无 RST 语义**——对端配合(收到 FIN 后其内核 close):`TIME_WAIT` ~150ms
→ 形态④ relisten(恢复全程 ~500ms);对端内核存活但不 close:芯片停
`FIN_WAIT_2` 长尾,**监听恢复受限于对端 close**,兜底 = 芯片 TIMEOUT/KeepAlive 拆
僵尸 30~90s(E13)——不是应用可加速的路径。
- 回归锚点:`TC-NETSOCK-240efg / 321 全组 / 460ef`(登记式、netTask 零占用、
client fd 旧形态保留);台架判据 = V5 复跑(e02_probe + FTP ≥30min)零 stall,
见 `docs/测试说明/实机测试实施指南.md` §4。
### 4.7 KeepAlive(服务器侧)