feat(net): 服务器侧 KeepAlive 转正(§5.56,E11)+ Phase 11 重开回归
E11(d96113b)证据链:"链路在、对端静默"注入下生产参数 60/5/3 实测 判死 ≈30s → TIM_OUT → QUARANTINE → pump 重建;静默但存活对端不误杀。 handle_connect_event LISTENING 分支按手册规定位置开启;反汇编确认 编译器把两分支尾部合并(LISTENING 跳入含 keepalive+fire_event 的公共 尾部,hex 全片仅该分支偏移 1 行差异,Code 尺寸不变属填充巧合)。 Phase 11 重开时发现其拉入 32KB s_rx_buf 超产品 RAM 余量(L6406E 链接 失败)→ 改专用 64B 探针缓冲(本 Phase 仅 64B 探针读,门控注释已留 "勿加回"警示),套件恢复 0 错 0 警;TC-NET-1101 步骤同步死对端注入法 (禁用网卡;Windows 防火墙规则对已建立连接无效,E11 实证)。 验证:产品/套件双构建 0 错 0 警 + 反汇编确认调用落地;台架确认 (:7003 静默对端判死 + Phase 11 实跑)待设备冷启动断电重上电后补做。
This commit is contained in:
@@ -3220,13 +3220,13 @@ static void handle_connect_event(net_sock_t *p_sock) {
|
||||
/* 读即清:本 Socket 中断状态寄存器 */
|
||||
(void)ch395f_get_sock_int_status(p_sock->ch395_sock);
|
||||
|
||||
/* ⚠ 曾在此按 §5.56 补 ch395f_set_keepalive_enable(sock,1)(服务器侧
|
||||
* KeepAlive),2026-10-12 实测后**撤回**:禁用网卡模拟真·静默死亡,
|
||||
* 芯片 +2 s 即报 TIM_OUT(≈ §5.17 重传 8×200 ms),本层随即释放重开
|
||||
* 监听——链路层失效本就被快速覆盖,KeepAlive 的 60 s 空转窗口对
|
||||
* 该失败模式无增益。依 Trap 25 铁律「不留未证明的复杂度」撤回。
|
||||
* 未覆盖的残余场景是"链路仍在、对端静默"(NAT/中间节点黑洞),
|
||||
* 本轮无法安全注入(见 Trap 记录「台架注入陷阱」)。 */
|
||||
/* §5.56:TCP 服务器须在 CONNECT 后开启 KeepAlive。2026-10-12 曾加后
|
||||
* 撤回(当时仅证明"物理断链"已被 +2s TIM_OUT 快速覆盖,其余场景
|
||||
* 无法注入、未证明);E11(2026-10-13,实验方案.md)用"禁用 PC 网卡"
|
||||
* 注入"链路在、对端静默"(NAT/黑洞)补上证据链:生产参数 60/5/3
|
||||
* 实测 ≈30 s 判死 → TIM_OUT → QUARANTINE → pump 重建;对端存活时
|
||||
* 探测被 ACK、空闲会话不误杀。消费链路现成,按手册位置转正。 */
|
||||
ch395f_set_keepalive_enable(p_sock->ch395_sock, 1);
|
||||
|
||||
/* 触发连接建立事件回调 */
|
||||
fire_event(p_sock, NET_EVENT_CONNECTED);
|
||||
|
||||
@@ -1081,9 +1081,9 @@ IDLE → ACCEPT → [SEND: 分块发 → DONE] / [RECV: 分块收+校验 → DON
|
||||
| 阶段 ID | TM-PHY-11 |
|
||||
|---------|-----------|
|
||||
| **类型** | PC 配合,netTask 运行 |
|
||||
| **耗时** | ~65 秒(60s idle + 15s probes) |
|
||||
| **入口** | `ENABLE_PHASE11_TESTS` |
|
||||
| **配置** | KeepAlive 空闲 60s,探测间隔 5s,3 次 |
|
||||
| **耗时** | ~65–80 秒(60s idle + 探测窗;芯片定时语义以实测为准,见 E11) |
|
||||
| **入口** | `ENABLE_PHASE11_TESTS`(2026-10-13 起默认开启;服务器侧开关由 net 层在 CONNECT 后自动置位,`docs/芯片手册/CH395F.md` §5.56) |
|
||||
| **配置** | KeepAlive 空闲 60s,探测间隔 5s,3 次(`net_config.h`) |
|
||||
|
||||
### TC-NET-1101: KeepAlive 触发断开
|
||||
|
||||
@@ -1093,9 +1093,9 @@ IDLE → ACCEPT → [SEND: 分块发 → DONE] / [RECV: 分块收+校验 → DON
|
||||
| **优先级** | P1 |
|
||||
| **类型** | 功能测试 |
|
||||
| **标题** | TCP 连接空闲超过 KeepAlive 阈值后自动断开 |
|
||||
| **前置条件** | 1. `ch395f_set_keepalive_idle(60000)`<br>2. `ch395f_set_keepalive_intvl(5000)`<br>3. `ch395f_set_keepalive_cnt(3)`<br>4. PC 连接后静置(不发数据) |
|
||||
| **测试步骤** | 1. PC 连接 8080,不发数据<br>2. 等待 KeepAlive 探测(60s idle + 3×5s = 75s 最大)<br>3. CH395F 接收 TIMEOUT → s0 → CLOSED → LISTEN |
|
||||
| **通过标准** | 超时时间 ≥ 60s,s0 回到 LISTEN |
|
||||
| **前置条件** | 1. `NET_KEEPALIVE_IDLE_MS=60000` / `INTVL=5000` / `CNT=3`(`net_config.h`)<br>2. 对端须为**死对端**:PC 连接 8080 后**禁用网卡**制造"链路在、对端静默"(存活对端会 ACK 探测 → 永不 TIMEOUT;Windows 防火墙规则对已建立连接无效,E11 实证)<br>3. 勿与 Phase 6/9/10/13 混选(recv 互抢数据) |
|
||||
| **测试步骤** | 1. PC 连接 8080,不发数据<br>2. 立即禁用 PC 网卡(中间有交换机 → 设备侧 PHY 链路保持)<br>3. 等待芯片报 TIM_OUT(从连接起 ≥60s;实测对端失联后判死 ≈30s)<br>4. 本层 QUARANTINE → pump 重建 → s0 回 LISTEN<br>5. 恢复网卡,重连 8080 验证端口已恢复 |
|
||||
| **通过标准** | recv 返回 0 且耗时 ≥ 60s;s0 回 LISTEN 且可接受新连接 |
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -433,9 +433,9 @@ CNT 次无 ACK"后产生 SINT_STAT_TIM_OUT / DISCONNECT。怀疑本仓没有利
|
||||
- 静默但**存活**的空闲会话不被误杀(T2)——因为对端会 ACK 探测包。
|
||||
- 2026-10-12 撤回的盲区(链路在、对端静默)**正是本机制覆盖的场景**;当年
|
||||
"+2s 即报 TIM_OUT"只覆盖了物理断链。
|
||||
- **建议采纳**:在 `handle_connect_event` 的 LISTENING 分支加回一行
|
||||
`ch395f_set_keepalive_enable(sock, 1)`(手册规定位置),并重新打开 Phase 11
|
||||
测试纳入回归;参数是否调优(如缩短 IDLE)由实测判死窗口需求决定。
|
||||
- **已采纳转正(2026-10-13,用户批准)**:在 `handle_connect_event` 的 LISTENING
|
||||
分支加回一行 `ch395f_set_keepalive_enable(sock, 1)`(手册规定位置),并重新打开
|
||||
Phase 11 测试纳入回归;参数是否调优(如缩短 IDLE)由实测判死窗口需求决定。
|
||||
- ⚠ 台架副作用:本轮反复实验后设备落入 E8 残渣风暴态(详见 E12),需**冷启动
|
||||
(断电重上电)**恢复,MCU 复位/RESET_ALL 不足以清除。
|
||||
|
||||
|
||||
@@ -229,15 +229,17 @@ CH395F 的 RECV 中断是电平触发的——只要接收缓冲区有数据就
|
||||
- **重传参数**:`SET_RETRAN_COUNT`(默认12次,最大20)和 `SET_RETRAN_PERIOD`(默认500ms,最大1000ms),总重传时间 = 次数 × 周期
|
||||
- **KeepAlive 参数必须为 500ms 的倍数**:`IDLE`(默认20000ms)、`INTVL`(默认15000ms),且 IDLE > INTVL;传入非 500 倍数的值导致 CH395F 内部定时器异常
|
||||
- **KeepAlive 默认关闭**:需在 `SINT_STAT_CONNECT` 后调用 `ch395f_set_keepalive_enable(sock, 1)` 启用
|
||||
- ⚠ **本仓现状与 E11 实测(2026-10-13)**:`ch395f_set_keepalive_enable` 全仓仅
|
||||
客户端分支(`CONNECTING`)调用,而 `App/` 无任何 `net_connect()` → **产品上
|
||||
KeepAlive 实际全程关闭**;服务器侧调用 2026-10-12 曾加后撤回(理由仅覆盖
|
||||
- ⚠ **E11 实测与转正(2026-10-13)**:此前 `ch395f_set_keepalive_enable` 全仓仅
|
||||
客户端分支(`CONNECTING`)调用,而 `App/` 无任何 `net_connect()` → 产品上
|
||||
KeepAlive 实际全程关闭;服务器侧调用 2026-10-12 曾加后撤回(理由仅覆盖
|
||||
物理链路失效)。E11 用"禁用 PC 网卡"注入"链路在、对端静默"(防火墙规则对
|
||||
已建立连接无效,见实验方案 E11 方法学),实测服务器侧开启后:生产参数
|
||||
60s/5s/3 → **判死 ≈30.0s**(早于手册公式 75s,以实测为准);短参数 6s/2s/2
|
||||
→ ≈5.1s(证明参数生效);静默但存活的对端**不被误杀**(90s 空闲 KEEPLIVE
|
||||
回显正常)。消费链路现成:TIM_OUT → `handle_timeout_event` QUARANTINE →
|
||||
pump relisten → 端口恢复。完整记录见 `docs/网络/N34-自愈审计/实验方案.md` E11。
|
||||
pump relisten → 端口恢复。**2026-10-13 转正**:`handle_connect_event`
|
||||
LISTENING 分支按 §5.56 开启,Phase 11 测试重新纳入回归(TC-NET-1101 步骤
|
||||
已更新死对端注入法)。完整记录见 `docs/网络/N34-自愈审计/实验方案.md` E11。
|
||||
|
||||
### Socket 4~7 缓冲区
|
||||
- CH395F 默认只给 Socket 0~3 分配独立收发缓冲(共 48 块 × 512B 用满),Socket 4~7 为零块
|
||||
|
||||
@@ -62,7 +62,9 @@ extern "C" {
|
||||
//#define ENABLE_PHASE8_TESTS /* [网] 大文件传输(100KB 文件收发) */
|
||||
//#define ENABLE_PHASE9_TESTS /* [网] Select/Poll I/O 多路复用 */
|
||||
//#define ENABLE_PHASE10_TESTS /* [网] 边界条件测试 */
|
||||
//#define ENABLE_PHASE11_TESTS /* [网] KeepAlive 超时断开测试 */
|
||||
#define ENABLE_PHASE11_TESTS /* [网] KeepAlive 超时断开:PC 连 8080 后须制造
|
||||
* 死对端(禁用网卡;防火墙规则对已建立连接无效,
|
||||
* E11 实证);勿与 Phase 6/9/10/13 混选(recv 互抢数据) */
|
||||
/* ---- 链路时延基线(M1;分段/阈值见 docs/测试说明/链路延迟测试说明.md)---- */
|
||||
//#define ENABLE_PHASE12_TESTS /* [硬] SPI 字节命令 / DMA 时延基线(L1/L2,无需 PC)—— M1 已完成,基线见说明文档 §6.1 */
|
||||
/* ---- 链路时延(M2/M3;分段/阈值见 docs/测试说明/链路延迟测试说明.md)---- */
|
||||
|
||||
+18
-12
@@ -43,8 +43,10 @@
|
||||
* 即首次使用 s_rx_buf)。P1-9 修复:原声明位于文件后段(Phase 8 注释块
|
||||
* 之后),phase6_run 使用先于声明 → ARMCC #20 identifier undefined,
|
||||
* 全部 NET 层测试配置不可编译。声明条件按各 Phase 实际用缓冲精确门控:
|
||||
* s_rx_buf —— Phase 6(Echo)/9(Select)/11(KeepAlive) 恒用,
|
||||
* Phase 8(大文件) 非 SEND 方向用;
|
||||
* s_rx_buf —— Phase 6(Echo)/9(Select) 恒用,
|
||||
* Phase 8(大文件) 非 SEND 方向用,Phase 10(边界) 用;
|
||||
* (Phase 11 只用 64B 探针读,2026-10-13 改专用小缓冲——
|
||||
* 产品 RAM 余量放不下 32KB,勿再把 11 加回本门控)
|
||||
* s_tx_buf —— Phase 8(大文件) 非 RECV 方向(填充发送窗口)及
|
||||
* Phase 10(边界) 用。
|
||||
* PHASE8_DIRECTION 由下方方向配置块定义(仅 ENABLE_PHASE8_TESTS 时);
|
||||
@@ -66,8 +68,7 @@
|
||||
|
||||
#if defined(ENABLE_PHASE6_TESTS) || \
|
||||
(defined(ENABLE_PHASE8_TESTS) && (PHASE8_DIRECTION != PHASE8_DIR_SEND)) || \
|
||||
defined(ENABLE_PHASE9_TESTS) || defined(ENABLE_PHASE10_TESTS) || \
|
||||
defined(ENABLE_PHASE11_TESTS)
|
||||
defined(ENABLE_PHASE9_TESTS) || defined(ENABLE_PHASE10_TESTS)
|
||||
static uint8_t s_rx_buf[TEST_BUF_SIZE];
|
||||
#endif
|
||||
/* s_tx_buf 仅 SEND/ECHO(及 Phase 10)需要;RECV 不发送,避免未使用变量警告 */
|
||||
@@ -791,19 +792,24 @@ static void phase10_run(int32_t sockfd) {
|
||||
/* ===================================================================
|
||||
* Phase 11 — TCP KeepAlive 超时断开
|
||||
*
|
||||
* 测试目的:验证 CH395F 的 TCP KeepAlive 机制:
|
||||
* 1. 连接空闲超过 idle 阈值(60s)后开始发送探测包
|
||||
* 2. 探测无响应(默认 3 次 × 5s = 15s)后触发 TIMEOUT
|
||||
* 3. Socket 自动关闭并回到 LISTEN
|
||||
* 测试目的:验证 CH395F 的 TCP KeepAlive 机制(服务器侧开关已由 net 层
|
||||
* 在 CONNECT 事件后按 §5.56 转正开启,E11 2026-10-13):
|
||||
* 1. 连接空闲超过 IDLE(60s)后芯片开始发送探测包
|
||||
* 2. CNT × INTVL(3 × 5s)无 ACK → SINT_STAT_TIM_OUT
|
||||
* 3. 本层 QUARANTINE → pump 重建 → 回 LISTEN
|
||||
*
|
||||
* 入口条件:Socket 0 处于 ESTABLISHED,PC 连接后静置(不发数据)。
|
||||
* 通过:KeepAlive 断开时间 ≥ 60s(从连接建立到 recv 返回 0 的间隔)。
|
||||
* 失败:不到 60s 就断开(可能是其他原因导致)或 75s 后仍未断开。
|
||||
* 入口条件:Socket 处于 ESTABLISHED 且对端为**死对端**——PC 连 8080 后
|
||||
* 禁用网卡(存活对端会 ACK 探测、TIMEOUT 永不触发,本测试将
|
||||
* 一直等待;防火墙规则对已建立连接无效,E11 实证)。
|
||||
* 通过:从连接建立到 recv 返回 0 的间隔 ≥ 60s(IDLE 阈值)。
|
||||
* 注:芯片定时语义与手册公式(75s)不完全一致,实测判死窗口见
|
||||
* 实验方案 E11(对端失联后 ≈30s)。
|
||||
* =================================================================== */
|
||||
|
||||
#ifdef ENABLE_PHASE11_TESTS
|
||||
static int32_t s_phase11_armed = 0;
|
||||
static uint32_t s_phase11_start = 0;
|
||||
static uint8_t s_phase11_buf[64]; /* 专用小缓冲:不占 32KB s_rx_buf(RAM 余量) */
|
||||
|
||||
static void phase11_run(int32_t sockfd) {
|
||||
/*
|
||||
@@ -818,7 +824,7 @@ static void phase11_run(int32_t sockfd) {
|
||||
return;
|
||||
}
|
||||
|
||||
int32_t n = net_recv(sockfd, s_rx_buf, 64, NET_MSG_DONTWAIT);
|
||||
int32_t n = net_recv(sockfd, s_phase11_buf, 64, NET_MSG_DONTWAIT);
|
||||
if (n == 0) {
|
||||
uint32_t elapsed = HAL_GetTick() - s_phase11_start;
|
||||
TEST_CHECK(elapsed >= 60000,
|
||||
|
||||
Reference in New Issue
Block a user