docs(net): 修正 FUN_PARA bit3 口径注释 + 补必要性论证
N-32 / B10 残余 P0 阶段:零风险的纯注释与文档口径修正。 net_socket.c:3627 / :3641 两处函数头注释写"CH395F 在 DISCONNECT 后自动关闭 Socket(FUN_PARA 默认)",与本仓 net_init 实际下发的 0x08(bit3 SOCKET_CLOSE=1,芯片不关、不清缓冲)相反。这类注释 会误导维护者跳过显式 close,是 U12 的观念源头。 新增设计文档 §2.4 回答"bit3=1 必要性大吗、如何安全处理": - bit3=0 时芯片当场清缓冲,FTP「发完即 FIN」尾部数据必被硬件 擦除且不可补救;bit3=0 也挡不住丢中断(Trap 22),孤儿态 照样有。故保持 0x08,改在软件层收口(结论并入 D4)。 - 安全处理 = 把契约落到不变量 I(session_dead 电平化)与 不变量 II(单一所有者 pump)+ 补 U12 的 close 对称。 验证:@build 0 错 0 警(Code=197084 与改前一致,纯注释); pre-commit 全绿(cppcheck / doc-links / C 规范)。
This commit is contained in:
@@ -3624,7 +3624,11 @@ static void handle_connect_event(net_sock_t *p_sock) {
|
||||
* 出口参数:无
|
||||
* 返回值:无
|
||||
* 限定条件:net_poll() 检测到 DISCONNECT 中断后调用;netTask 上下文
|
||||
* 函数说明:1. CH395F 在 DISCONNECT 后自动关闭 Socket(FUN_PARA 默认),需重新 OPEN + LISTEN
|
||||
* 函数说明:1. ⚠ FUN_PARA bit3=1(本仓 net_init 置 0x08):DISCONNECT/TIM_OUT 后芯片
|
||||
* **不**关 Socket、**不清**缓冲(停 0x05/0x00)——残留数据须由本层读出后,再由
|
||||
* 本层 ch395f_close_socket 关闭;芯片不代劳(§5.52② / §5.23)。旧注释写"CH395F 在
|
||||
* DISCONNECT 后自动关闭 Socket(FUN_PARA 默认)"与实际 0x08 相反,2026-10-12 修正:
|
||||
* 它会误导维护者跳过显式 close(= U12 的成因之一)。之后需重新 OPEN + LISTEN
|
||||
* 2. 单连接:置 CLOSED,交由 net_recv_locked 排空剩余数据后再关
|
||||
* 3. 触发 NET_EVENT_DISCONNECTED 回调
|
||||
*/
|
||||
@@ -3638,7 +3642,7 @@ static void handle_disconnect_event(net_sock_t *p_sock) {
|
||||
|
||||
/* 监听态:DISCONNECT 落在监听器上 */
|
||||
if (p_sock->state == NET_SOCK_STATE_LISTENING) {
|
||||
/* Trap 22 / N-6:监听态收到 DISCONNECT——芯片断开后自动关闭该 Socket(FUN_PARA 默认),不重开则监听永久死亡(此后所有 SYN 被拒);
|
||||
/* Trap 22 / N-6:监听态收到 DISCONNECT——bit3=1(0x08)下芯片**不**关该 Socket(停 0x05/0x00,芯片 TCP 侧已 CLOSED);不重开则此后所有 SYN 全被拒 = 监听永久死亡;
|
||||
* 触发 = 断连后 <~1s 快速复连时 CONNECT 中断未上报(控制块滞留 LISTENING)后该连接断开(2026-09-23 生产固件复现);
|
||||
* → 回读芯片状态:监听已失位即重建(D10 非阻塞重试),仍在监听判陈旧丢弃 */
|
||||
/* 回读缓冲(芯片状态 2 字节) */
|
||||
|
||||
@@ -67,6 +67,59 @@ B10 探针看到的"孤儿芯片态"不是芯片异常,而是本仓这个配
|
||||
→ Trap 25 的 `net_lost_connect_probe`(`:1250-1289`)对这个端口**从不运行**,
|
||||
丢 CONNECT 只剩对账②。:21/:8888 因为无条件轮询 accept,探针才活着。
|
||||
|
||||
### 2.4 FUN_PARA bit3=1 的必要性与安全边界(2026-10-12 评估,结论:**必须保留 0x08**)
|
||||
|
||||
> 用户提问:「bit3 在本项目设置为 1 的必要性大吗?会导致这么多问题;如果设为 1,
|
||||
> 如何安全处理?」本节以手册原文 + 实测证据回答,并把它并入决策记录 D4。
|
||||
|
||||
**① 必要性 = 硬性必需,不是可调项。** 手册对 bit3 的分流写得很直白:
|
||||
|
||||
- `docs/芯片手册/CH395F.md` §5.52 注释②:「此位为 0 表示在产生 SINT_STAT_DISCONNECT 或者 SINT_STAT_TIM_OUT 中断后,
|
||||
CH395 会主动关闭 Socket。……**关闭 Socket 就意味着 CH395 会将此 Socket 内部缓冲区和
|
||||
一些相关变量清除**,在某些应用中,如果 CH395 内部自行关闭 Socket 可能会导致残留的数据
|
||||
被强行清除。这种情况下可以将该位置 1,**由单片机将数据读出来,然后再关闭 Socket**。」
|
||||
- `docs/芯片手册/CH395F.md` §5.23 L572 同向:「为 0 则……主动将 Socket 状态置为关闭状态**并将相关缓冲区全部清除**;
|
||||
反之则不会对 Socket 状态和相关缓冲区做任何操作,以方便外部单片机……**将残留的数据读出**。」
|
||||
|
||||
实测现场(Trap 25 三次定案的判别探针):`st=0x05/0x00` 且 `recv_len=1027`——
|
||||
Socket 仍 OPEN、芯片 TCP 已 CLOSED、**RX 缓冲里 STOR 载荷一个不少**。这正是 bit3=1 按规格
|
||||
保留现场,不是芯片异常(`docs/问题记录/CH395F_Trap_Records.md` §877-878)。
|
||||
|
||||
**② bit3=0 的代价是「硬件保证的数据丢失」,且不可在软件层补救。**
|
||||
本产品最典型的流量形态是「发完即 FIN」:ftplib `storbinary` 语义 = `sendall` 发完立即关
|
||||
数据连接、回控制通道等 226。芯片把最后一段数据落进 RX 的同时抛出 DISCONNECT:
|
||||
|
||||
- bit3=1:RX 数据在,MCU 来得及读(Trap 23 的「排空 RX 再 close」修复才成立);
|
||||
- bit3=0:芯片**当场**关 Socket 并清缓冲 → MCU 永远读不到尾部 → 文件被截断却仍回报 226
|
||||
(静默损坏)。这是 bit3=0 的**必然结果**,不是概率问题——软件再聪明也拿不回已被硬件擦掉的数据。
|
||||
|
||||
即:改 bit3=0 等于用「一个硬件保证、不可修的数据丢失」去换「一个软件侧可修的关闭义务」,
|
||||
严格更差。:8888 对时包、:7003 远显推流同样是「数据 + 随即关闭」形态,一并受害。
|
||||
|
||||
**③ bit3=0 也并不能真正消除孤儿态。** 芯片自动关以**收到** DISCONNECT/TIM_OUT 为前提,
|
||||
而 Trap 22 已实证快速复连场景芯片会**丢**这两个中断(`docs/问题记录/CH395F_Trap_Records.md`
|
||||
B10 行)→ 中断丢了,bit3=0 同样停在已关/半关态,孤儿 Socket 照样存在。
|
||||
它只是降低出现概率,代价却是上面第②条。
|
||||
|
||||
**④ 所以「这么多问题」不归 bit3=1。** 断开后停 `0x05/0x00` 是 bit3=1 的**合法后果**(D4);
|
||||
真正造成 B10 永久拒连、消费者卡死、EOF 被吞没的,是软件侧没把「该由 MCU 关 Socket」这条
|
||||
义务落到唯一所有者——重建所有者 12 个、无人负责组合 15 个(§2.3),以及 U12 的「relisten
|
||||
的 LISTEN 失败不 close 芯片 Socket」与 open 失败路径不对称。bit3=1 只是把义务显式化,
|
||||
把原本被芯片掩盖的架构欠债照了出来。
|
||||
|
||||
**⑤ 安全处理 = 把 bit3=1 的契约在软件侧收口**(即 §4 的两条不变量,逐条对应上面的缺口):
|
||||
|
||||
| 契约要求 | 对应缺口 | 收口手段 |
|
||||
|---|---|---|
|
||||
| 「会话结束」必须被**谁都能看见**,不能只在边沿那一刻 | EOF 边沿化:抢先 relisten → recv 永久 `WOULDBLOCK`(§2.3) | 不变量 I:`net_sock_t.session_dead` 粘滞电平,`net_recv_locked` DONTWAIT 判据改 `state==CLOSED \|\| session_dead`(P1) |
|
||||
| 关闭 Socket 必须**一定有人做**、且只做一次 | 重建所有者 12 个 + U12 的 LISTEN 失败不回 close | 不变量 II:`net_listener_pump` 单点重建 + 补 U12 的 close 对称(P2) |
|
||||
| 关闭姿势必须正确 | Trap 14/17:陈旧 DISCONNECT 锁存秒断下一条连接 | `net_close_locked` 既有「close → 等 `CLOSED` → 排空本 Socket 中断」,是 bit3=1 下唯一正确的关闭序列 |
|
||||
| 异常释放须先排空残渣再关 | Trap 23:~2KB RX 残渣被下条连接当自己的数据读走 | `net_relisten_locked` 隔离期(400 ms)持续排空 RX + 主动 close + 等 `CLOSED/TCP_CLOSED` |
|
||||
|
||||
**⑥ 本次(P0)已落地的口径修正**:`net_socket.c:3627` / `:3641` 原注释写「DISCONNECT 后
|
||||
芯片自动关闭 Socket(FUN_PARA 默认)」——与实际 `0x08` **相反**。这类注释正是 U12 这类
|
||||
「跳过显式 close」缺陷的观念源头,已改正并留痕。
|
||||
|
||||
## 3. 为什么不能走"芯片原生多连接模式"(A′)
|
||||
|
||||
芯片确实自带 lwIP 式模型:FUN_PARA bit1(≥0x44,本仓实测 0x4A)下
|
||||
@@ -194,7 +247,7 @@ DONTWAIT 在 LISTENING 下返 `WOULDBLOCK`(`:1890`)→ `ui_net_sink.c:560-56
|
||||
| D1 | **A′(启用芯片多连接模式)出局**,根治必须在单连接复用模型内做 | `docs/问题记录/CH395F_Trap_Records.md` 附 FTP 改造清单第 4 条「多连接模式不支持多监听」;本产品 3 常驻监听 + 动态 PASV;§9.2.6 L1295 池按源端口匹配会互串;历史实测 Trap 02/11;FUN_PARA 初始化后不可改(`docs/芯片手册/CH395F.md` §5.52 L795⑥) |
|
||||
| D2 | 采用**形态 B 深化**(电平化 + 单一所有者),**不做 P3** | P3 需控制面重写、RAM/Flash 上升,只有"同端口并发多连接"需求才值得 |
|
||||
| D3 | 对账④**保留**(`4f2cc8b` 不撤回),其副作用由 P1 消除 | Trap 22 实证事件会丢 → 周期对账不可删;④ 已把 `:7003` 从 0/10 永久死拉到 10/10 |
|
||||
| D4 | `FUN_PARA` **保持 `0x08`**,不因孤儿态改配置 | bit3=1 是 Trap 18/25 定案的"保留排空现场"契约;孤儿态是它的合法后果,应在软件层收口而非回退契约 |
|
||||
| D4 | `FUN_PARA` **保持 `0x08`**,不因孤儿态改配置(2026-10-12 复核确认) | bit3=1 是 Trap 18/25 定案的"保留排空现场"契约;bit3=0 会令芯片在 DISCONNECT/TIM_OUT 时**当场清缓冲**(`docs/芯片手册/CH395F.md` §5.52② / §5.23 L572)→「发完即 FIN」流量的尾部数据必被硬件擦除、**不可补救**;且 bit3=0 也挡不住丢中断(Trap 22)→ 孤儿态照样有。孤儿态是 bit3=1 的合法后果,应在软件层收口而非回退契约。完整论证见 §2.4 |
|
||||
| D5 | 顺序 **P0 → P1 → P2**,每阶段独立提交、独立回归、可单独回滚 | P1 不动 fd 模型却消掉两类事故,性价比最高 |
|
||||
| D6 | 真机/模拟器**双模型分裂暂不消除** | 消除即等于做 P3;先靠 P1 把应用侧契约对齐 |
|
||||
| D7 | 同族残留**不在本次根治范围**,各自单列:U1(CONNECTING 滞留,B2 残余)、U11、U12、U14、U15,以及审计项 B4/B5/B6/B7/B8/B9 | 与监听生命周期不同因,混做会让回归面失控 |
|
||||
@@ -202,7 +255,7 @@ DONTWAIT 在 LISTENING 下返 `WOULDBLOCK`(`:1890`)→ `ui_net_sink.c:560-56
|
||||
## 9. 执行清单(后续按此执行,逐项勾选)
|
||||
|
||||
**P0(零风险)**
|
||||
- [ ] 修 `Drivers/BSP/NET/net_socket.c:3627`、`:3641` 的 FUN_PARA 口径错误注释(实际 `0x08`,芯片**不**自动关)
|
||||
- [x] 修 `Drivers/BSP/NET/net_socket.c:3627`、`:3641` 的 FUN_PARA 口径错误注释(实际 `0x08`,芯片**不**自动关)—— 2026-10-12 已改并留痕(§2.4⑥),`@build` 0 错 0 警
|
||||
- [ ] 把 U11 / U12 / U14 / U15 登记进 `docs/问题记录/CH395F_Trap_Records.md`
|
||||
- [ ] 在 B10 行确认已记「④ 扩大 EOF 吞没窗口」(已记,执行时复核)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user