Trap23两阶段修复: 异常释放400ms隔离+正常释放100ms沉降(仅收过数据), 修复中止后新传输首笔静默截断

This commit is contained in:
2026-09-25 01:57:03 +08:00
parent d0cbeb6b5b
commit a1f1f46262
2 changed files with 73 additions and 7 deletions
+37
View File
@@ -664,3 +664,40 @@ NET 层 TCP Client(阶段 7)`net_connect()` 返回 0,但 `net_poll()` 报
- 修复后:RST 中止 **10/10**、优雅 FIN 中止 **5/5** 全部通过;
- 正常路径回归:30×64KB 零间隔 **30/30**、20×64KB **20/20**,SHA-256 全匹配;
- 启动门禁:`App init OK` / `net init: OK`、FORBID 0 行。
### 第二阶段:正常释放(FIN)路径——边界甄别与 100ms 沉降(2026-09-24)
**边界再甄别(现场"1~2s"时间假设被推翻)**:中止后 gap 500/2000/5000ms 台架复测 → 设备实存尺寸**全部仍 2048**(各 4/4,合计 12/12)→ **与时间无关**;监听重开本征即时(`t_accept` 30~47ms)。真实边界:
| 维度 | 结论 | 证据 |
|---|---|---|
| 触发 | 设备侧**收过数据**的数据连接被对端关闭(纯 FIN 即触发,不要求 RST) | 纯 `close()`(FIN)4/4 复现;RST 变体 5/5 |
| 受影响路径 | 仅**正常 DISCONNECT 释放路径**缺芯片状态沉降 | RST(TIMEOUT)路径已有一阶段 400ms 隔离保护 |
| 投递形式 | 芯片上一条连接的收尾残留,投递给**复用同一 fd 的下一条**连接(accept 后约 10~20ms 一条伪 DISCONNECT) | 设备日志:`standalone accept` → `DISCONNECTED, releasing (chip tcp=0x00)` |
| 影响面 | **一次性**(首条新连接中招,第二条起干净);同 fd 非 FTP 服务(`:7003` UI sink)不受影响(其 socket 不按传输复用) | 一次性 3/3 全对;`:7003` 复用 8/8 全过 |
| 时间 | 无关(gap 5s 仍失败)→ 现场"1~2s"只是人工重触的常见窗口,不是芯片机制 | gap 500/2000/5000ms 共 12/12 全部失败 |
**修复(第二阶段,`Drivers/BSP/NET/net_socket.c` +36/−7,netTask 串行上下文,零新增缓冲)**:
1. relisten 前沉降分两级:异常释放(芯片 TIMEOUT)=清理 + 最短等 400ms(`NET_RELISTEN_QUARANTINE_MS`,一阶段行为不变);正常释放(芯片 DISCONNECT)=清理 + 最短等 **100ms**(`NET_RELISTEN_GRACEFUL_MS`,新增);
2. 正常释放沉降**仅在本连接收过数据时登记**(`recv_bytes != 0`):纯连接即关(Trap 22 的 0ms 复连用例)与只发不收的下载连接无残留 → 免沉降保住快速复连时序;
3. 日志区分 `relisten settle`(正常)/ `relisten quarantine`(异常),便于台架分辨触发路径。
**沉降值实测悬崖**(只清理不等待 = 0ms):0ms **无效**(4/4 仍截断)→ 30ms 仍失败(4/4)→ **100ms 通过**(多轮稳定)→ 取 100ms(对 30ms 重试节拍 `NET_RELISTEN_RETRY_MS` 留 3× 余量)。
**验证(第二阶段后;设备日志 `UPLOAD '<path>' N bytes OK` 为权威真值)**:
| 用例 | 修复前 | 修复后 |
|---|---|---|
| FIN 关闭后**首笔**上传 ×8 | **0/8**(实存 2048 + 回报 226) | **8/8**(实存 4096,sha OK) |
| 纯 `close()` 变体 ×4 | 中招 | **4/4** |
| `ftp_abort_probe --graceful` ×5 | **0/5** | **5/5** |
| `ftp_abort_probe`(RST)×5 | 5/5(一阶段) | **5/5** |
| 无中止对照 ×4 / 一次性连发 3 笔 ×1 | 4/4 / 第 1 笔坏 | **4/4 / 3/3** |
| 正常往返 freeze 4096×4 / 64KB×2 | 通过 | **4/4 / 2/2**(t_stor 0.68→**0.18s**,t_retr 1.13→**0.19s**) |
| 非 FTP `:7003` sink 复用 ×8(RST+FIN) | 8/8 | **8/8** |
| Trap 22:`:21` 0ms×50 / 100ms×50,`:7003` 300ms×10,`:8888` 0ms×20 | 50/50 / 50/50 / 10/10 / 20/20 | **50/50 / 50/50 / 10/10 / 20/20** |
| 启动门禁 / 控制台 / 堆 | — | `App init OK` / `net init: OK`,FORBID **0**,`CONSOLE dropped 0`,`heap free=8776 min_ever=4816` |
**结论**:缺陷位于 **fd 复用生命周期**(芯片上一条连接的残留状态投递给下一条连接),不在 FTP 命令逻辑——lftpd 只是把它放大成误报 226。RST/TIMEOUT 半边由一阶段隔离处理,DISCONNECT 半边由本阶段沉降处理,合计覆盖全部"收过数据后关闭"的释放路径。已知残余边界:中止那一笔 STOR 自身仍回报 226(STOR 无长度声明、在途 FIN 与正常完成不可区分)——后续硬化见待办 #3。
**对应文件**:`Drivers/BSP/NET/net_socket.c`(`handle_disconnect_event` 沉降登记 + `net_relisten_locked` 两级沉降);`MDK-ARM/ftp_abort_probe.py` / `MDK-ARM/bench_diag_abort_gap.py`(边界甄别与回归判据)。