fix(NET): 监听重建单一所有者收口 + 沉降窗 800ms 上限只留痕
T0 降噪 + T1 单一所有者:四处重建触发(recon/accept/eof/drop)与 pending 第五处统一走 net_listener_request(),由 net_listener_tick 单点执行; 沉降重试日志改"只留首末"(E0 口径),每次恢复少打 3 行重复行。 force open 降级为只留痕(E19 反事实 A/B 实测):芯片未回 CLOSED 时强行 open 注定吃 USE 错(TRAP-NET-09),放行与不放行的端口恢复时刻同一分布 (放行 +512 / 不放行 +505·533 / 降级后 +509 ms)——恢复由芯片何时回 CLOSED 决定。真正兜住"监听器永久失效"的是 D10 预算到期 + 对账形态④ 重新登记,不是放行。新增 s_relisten_capped[] 使上限留痕只打一次, 隔离标志不清 → 下一轮继续排空残渣(构建 B 实测每 30ms 两行会刷屏)。 负向注入三轮打靶(E18,注入代码不入库):形态① 吞掉 DISCONNECT 后 4/4 救回、③ 空闲监听器静默失位两轮独立复现、⑤ 开盲区吞掉芯片自发中断 + 收回 LISTEN 后 -> resync 命中且挂起 recv 被取消 → 三条均不可降级为 只留痕。顺带稳定复现 [ERR] relisten retry budget exhausted = 对端不配合 拆链的签名,非回归。 台架:boot PASS;ftp_abort_probe RST 10/10 + FIN 5/5;relisten_stress :21 50/50(p50 507ms);n30_repro 30/30。构建 0 错 0 警 Code=212316; netTask 静态最坏链 1920→1912 B;RAM 台账受管区已 --write 同步(RW +8B)。 文档:E17/E18/E19 三行 + §4.1 常态 0 命中归因 + §4.3 兜底归属改正; 登记簿 N-31 销项(结论沉淀进 §4.3 与 E19)。
This commit is contained in:
+128
-82
@@ -2,22 +2,26 @@
|
||||
* 模块名称:Network Listener Lifecycle
|
||||
* 模块功能:监听器生命周期(真机专属)—— 维持 fd 处于 LISTEN 态的全部机制:
|
||||
* 重建(open+listen)、重建前的沉降/隔离(TRAP-NET-18)、排空 RX 残渣、
|
||||
* D10 非阻塞重试(周期性重建决策者=自愈收敛阶段 3 合并后的
|
||||
* net_reconcile_tick,见 net_socket.c)。
|
||||
* D10 非阻塞重试。**本模块是唯一的执行者**:外部只登记请求,动作只在本
|
||||
* 模块的 net_listener_tick 一处发生(周期性"该不该重建"的判据仍在
|
||||
* net_reconcile_tick 形态③④,见 net_socket.c)。
|
||||
* 适用平台:STM32F407ZGTx + CH395F 以太网芯片
|
||||
* 作者:王建锋
|
||||
* 创建日期:2026-10-12
|
||||
* 修改记录:
|
||||
* 2026-10-12 王建锋 从 net_socket.c 整体抽出监听生命周期(N-32 §10 模块化)
|
||||
* 2026-10-13 王建锋 自愈收敛阶段 3:pump 并入 net_reconcile_tick(《网络自愈架构设计》§4.1)
|
||||
* 2026-10-14 王建锋 单一所有者收口(《网络自愈架构设计》§4.2 I2 加强):try 当场动作
|
||||
* + 四处调用点各自带门 → request 登记意图 + tick 唯一执行;
|
||||
* 沉降留痕改"只留首末"(实测每次恢复 3 行 → 1 行)
|
||||
*
|
||||
* 职责与边界见 net_listener.h 头注释;设计依据见
|
||||
* docs/网络/网络自愈架构设计.md §11。
|
||||
*
|
||||
* 模块内分层:
|
||||
* ① 策略常量与私有状态(s_relisten_*)
|
||||
* ② 机制:net_drain_chip_rx(排空)/ net_relisten_locked(重建一次)
|
||||
* ③ 对外接口:settle / try / clear / retry_tick
|
||||
* ② 机制:net_drain_chip_rx(排空)/ net_relisten_locked(重建一次,只由 tick 调)
|
||||
* ③ 对外接口:settle / request / clear / tick
|
||||
*
|
||||
* 依赖(全部为单向,无反向 include):
|
||||
* net_types.h(net_sock_t)/ net_socket.h(net_get_sock / NET_MAX_SOCKETS /
|
||||
@@ -70,20 +74,21 @@
|
||||
static uint8_t s_relisten_quarantine[NET_MAX_SOCKETS]; /* 0=免清;1=异常释放;2=正常释放 */
|
||||
static uint32_t s_relisten_settle_start[NET_MAX_SOCKETS]; /* 隔离起点(0 = 未开始) */
|
||||
static uint32_t s_relisten_settle_dead[NET_MAX_SOCKETS]; /* 隔离上限到期时刻 */
|
||||
static uint8_t s_relisten_capped[NET_MAX_SOCKETS]; /* 1=上限留痕已打(只留首末,防 30ms 刷屏) */
|
||||
|
||||
/* ===== TRAP-NET-09 非阻塞重监听重试(D10 修复,2026-09-22 M3 实测) =====
|
||||
* 旧实现:open 失败 → close → osDelay(500) → 重试,netTask 忙等 500ms(全网冻结)
|
||||
* 且实测恢复 588ms、期间客户端重连被拒
|
||||
* 新实现:首次失败即登记待重试,由 netTask 每轮 net_process_messages() 到点重试
|
||||
* 新实现:外部只登记请求(net_listener_request),由 netTask 每轮 net_listener_tick 执行
|
||||
* 恢复时间 ≈ NET_RELISTEN_RETRY_MS 量级,任何时刻都不阻塞任务
|
||||
*/
|
||||
#define NET_RELISTEN_RETRY_MS 30U /* 重试间隔(TRAP-NET-09 沉降窗口;实测 100ms 首次必成,
|
||||
* 收紧到 30ms 以缩短恢复时间——未成则下一轮到点再来) */
|
||||
#define NET_RELISTEN_DEADLINE_MS 2000U /* 放弃时限(自首次尝试起) */
|
||||
|
||||
static uint8_t s_relisten_wait[NET_MAX_SOCKETS]; /* 1 = 有待重试的重监听 */
|
||||
static uint32_t s_relisten_next[NET_MAX_SOCKETS]; /* 下次重试时刻(tick) */
|
||||
static uint32_t s_relisten_dead[NET_MAX_SOCKETS]; /* 放弃时刻(tick) */
|
||||
static uint8_t s_relisten_req[NET_MAX_SOCKETS]; /* 0=无请求;非 0=请求来源+1(net_listener_req_t) */
|
||||
static uint32_t s_relisten_next[NET_MAX_SOCKETS]; /* 下次尝试时刻(tick;0=立即) */
|
||||
static uint32_t s_relisten_dead[NET_MAX_SOCKETS]; /* 放弃时刻(tick;0=尚未起算) */
|
||||
#if defined(TEST_LATENCY_PROBE)
|
||||
static lat_tmark_t s_relisten_mark[NET_MAX_SOCKETS]; /* 恢复计时起点(首次尝试) */
|
||||
#endif
|
||||
@@ -133,7 +138,8 @@ static void net_drain_chip_rx(int sockfd) {
|
||||
* 2. 仅将 state 置回 LISTENING,不 memset(fd 与 auto_relisten 保持不变)
|
||||
* 3. 实现 BSD 风格"监听 Socket 常驻",应用层无需手动重监听
|
||||
* 4. **单次尝试**:失败立即返回(不 osDelay 忙等)
|
||||
* 5. TRAP-NET-09 沉降交给 net_listener_try / net_listener_retry_tick 非阻塞重试(见下)
|
||||
* 5. **只由 net_listener_tick 调用**(唯一执行者);TRAP-NET-09 沉降由它的
|
||||
* 30ms 节奏重试(见文件末 net_listener_tick)
|
||||
* 6. 旧实现在此 osDelay(500) 忙等,netTask 冻结 500ms、实测恢复 588ms(M3 台架 D10)
|
||||
* 7. N-32 §10:fd 由参数传入(不再用 `p_sock - s_net_socks` 反推),
|
||||
* 控制块经 net_get_sock() 取 —— 本模块**不访问** net_socket.c 的 static 数组
|
||||
@@ -157,6 +163,8 @@ static int net_relisten_locked(int sockfd) {
|
||||
uint32_t now = HAL_GetTick();
|
||||
/* 隔离等级(1=异常释放 2=正常释放) */
|
||||
uint8_t lvl = s_relisten_quarantine[sockfd];
|
||||
/* 是否隔离期首轮:留痕只打首轮(E0 结论「重试日志只留首末」,2026-10-14 落地) */
|
||||
uint8_t first = (s_relisten_settle_start[sockfd] == 0U) ? 1U : 0U;
|
||||
/* 最短等待由释放来源决定(NET_RELISTEN_SETTLE_*):异常释放 400ms(等在途数据落尽)
|
||||
* 正常释放 100ms(等芯片内部收尾) */
|
||||
uint32_t hold = (lvl == NET_RELISTEN_SETTLE_QUARANTINE) ? NET_RELISTEN_QUARANTINE_MS
|
||||
@@ -192,23 +200,42 @@ static int net_relisten_locked(int sockfd) {
|
||||
((uint32_t)(now - s_relisten_settle_start[sockfd]) < hold))) {
|
||||
/* 未到上限:交重试轮询(30ms 后复检) */
|
||||
if ((int32_t)(now - s_relisten_settle_dead[sockfd]) < 0) {
|
||||
DBG_INFO("sock%d relisten %s (sock=0x%02X tcp=0x%02X)",
|
||||
sockfd, tag, st[0], st[1]);
|
||||
/* 只留首轮一行:实测每次恢复原本要打 3 行同样内容(E0 已定"重试日志
|
||||
* 只留首末");末行由下面的 force open 或成功行给出,中间轮次静默 */
|
||||
if (first != 0U) {
|
||||
DBG_INFO("sock%d relisten %s (sock=0x%02X tcp=0x%02X)",
|
||||
sockfd, tag, st[0], st[1]);
|
||||
}
|
||||
/* 置 BUSY(结果回传调用方) */
|
||||
(void)net_set_errno(NET_ERR_BUSY);
|
||||
/* 交重试轮询(30ms 后复检) */
|
||||
return -1;
|
||||
}
|
||||
/* 隔离上限已至:强制放行(防监听器永久失效) */
|
||||
DBG_INFO("sock%d relisten %s timeout, force open (sock=0x%02X tcp=0x%02X)",
|
||||
sockfd, tag, st[0], st[1]);
|
||||
/* 隔离上限已至:**只留痕,不强行放行**(E19 反事实 A/B 实测,2026-10-14):
|
||||
* 芯片未回 CLOSED 时强行 open 注定吃 USE 错(TRAP-NET-09),放行与不放行的
|
||||
* 端口恢复时刻同一分布(+512 vs +505/533 ms)——恢复由"芯片何时回 CLOSED"决定。
|
||||
* 故继续留在隔离期边等边排渣,交 D10 重试轮询。**"监听器不会永久失效"的真正
|
||||
* 兜底 = D10 预算到期 + 对账形态④ 重新登记**(构建 B 实测:抑制后仍持续重试
|
||||
* 并最终恢复),不是这里放行——勿再把本处当兜底。
|
||||
* ⚠ 上限留痕只打一次:每 30ms 重试一轮若都留痕会刷屏(构建 B 实测两行/30ms) */
|
||||
if (s_relisten_capped[sockfd] == 0U) {
|
||||
s_relisten_capped[sockfd] = 1U;
|
||||
DBG_INFO("sock%d relisten %s timeout, keep waiting (sock=0x%02X tcp=0x%02X)",
|
||||
sockfd, tag, st[0], st[1]);
|
||||
}
|
||||
/* 置 BUSY(结果回传调用方) */
|
||||
(void)net_set_errno(NET_ERR_BUSY);
|
||||
/* 交重试轮询(30ms 后复检);隔离标志**不清** → 下轮继续排空残渣 */
|
||||
return -1;
|
||||
}
|
||||
/* 隔离完成(或强制放行) */
|
||||
/* 隔离完成(芯片已回 CLOSED 且已满最短等待) */
|
||||
s_relisten_quarantine[sockfd] = 0U;
|
||||
/* 清隔离起点(回到"未开始") */
|
||||
s_relisten_settle_start[sockfd] = 0U;
|
||||
/* 清上限时刻 */
|
||||
s_relisten_settle_dead[sockfd] = 0U;
|
||||
/* 清上限留痕标志(下一轮隔离可重新留一次痕) */
|
||||
s_relisten_capped[sockfd] = 0U;
|
||||
}
|
||||
|
||||
/* 重置协议类型为 TCP */
|
||||
@@ -273,8 +300,8 @@ static int net_relisten_locked(int sockfd) {
|
||||
p_sock->recv_bytes = 0;
|
||||
/* auto_relisten 保持为 1,下次断连仍自动重监听 */
|
||||
|
||||
/* 留痕:监听器重建完成 */
|
||||
DBG_INFO("sock%d auto-relisten ok", sockfd);
|
||||
/* 成功留痕由唯一执行者 net_listener_tick 打(带登记来源):本函数此前也打一行,
|
||||
* 与 tick 的"retry ok"是同一事实的两行(实测每次恢复 2 行 → 合并为 1 行) */
|
||||
/* 重监听成功 */
|
||||
return 0;
|
||||
}
|
||||
@@ -288,8 +315,7 @@ static int net_relisten_locked(int sockfd) {
|
||||
* 出口参数:无
|
||||
* 返回值:无
|
||||
* 限定条件:netTask 上下文;由 handle_disconnect_event / handle_timeout_event 调用
|
||||
* 函数说明:1. 只置事实,不做动作 —— 重建由 net_reconcile_tick(形态③④)/
|
||||
* net_listener_try 负责
|
||||
* 函数说明:1. 只置事实,不做动作 —— 动作只在本模块 net_listener_tick 一处发生
|
||||
* 2. 越界 sockfd 静默忽略
|
||||
*/
|
||||
void net_listener_settle(int sockfd, net_listener_settle_t level) {
|
||||
@@ -307,15 +333,15 @@ void net_listener_settle(int sockfd, net_listener_settle_t level) {
|
||||
* 出口参数:无
|
||||
* 返回值:无
|
||||
* 限定条件:无
|
||||
* 函数说明:1. 清"待重试"标志与重试时刻,fd 关闭/新建时调用(防残留重试)
|
||||
* 函数说明:1. 清重建请求登记与重试时刻,fd 关闭/新建时调用(防残留请求)
|
||||
*/
|
||||
void net_listener_clear(int sockfd) {
|
||||
/* 描述符越界:直接返回(本函数不设错误码) */
|
||||
if ((sockfd < 0) || (sockfd >= NET_MAX_SOCKETS)) {
|
||||
return;
|
||||
}
|
||||
/* 清"待重试"标志 */
|
||||
s_relisten_wait[sockfd] = 0U;
|
||||
/* 清重建请求登记 */
|
||||
s_relisten_req[sockfd] = 0U;
|
||||
/* 清下次重试时刻 */
|
||||
s_relisten_next[sockfd] = 0U;
|
||||
/* 清放弃时刻 */
|
||||
@@ -324,6 +350,8 @@ void net_listener_clear(int sockfd) {
|
||||
s_relisten_settle_dead[sockfd] = 0U;
|
||||
/* 清沉降起点 */
|
||||
s_relisten_settle_start[sockfd] = 0U;
|
||||
/* 清上限留痕标志(防同 fd 下一生成继承"已留痕"而静默) */
|
||||
s_relisten_capped[sockfd] = 0U;
|
||||
/* 一并清隔离标志:关闭/重建即确定性释放,
|
||||
* 防同 fd 下一生成继承上轮的 400/800ms
|
||||
* 隔离等待(2026-09-24 台架发现跨轮残留) */
|
||||
@@ -348,98 +376,104 @@ static void net_relisten_done(int sockfd) {
|
||||
}
|
||||
|
||||
/*
|
||||
* 函数功能:尝试重建监听一次(**不阻塞**);失败则登记"待重试"(契约见 net_listener.h)
|
||||
* 函数功能:登记「本 fd 期望回到 LISTEN」(**只登记意图,不碰芯片**;契约见 net_listener.h)
|
||||
* 入口参数:sockfd - Socket 描述符 (0~7) int
|
||||
* reason - 登记来源(net_listener_req_t,仅用于留痕归因)
|
||||
* 出口参数:无
|
||||
* 返回值:0 - 成功(监听器已就绪);-1 - 本次失败或已在重试队列中 int
|
||||
* 限定条件:netTask 上下文;fd 为监听型(auto_relisten)
|
||||
* 函数说明:1. 已在重试队列时直接返回 -1(不重复尝试、不重置重试时刻)——
|
||||
* 否则每 10ms 一次的 accept 轮询会不断把重试时刻往后推,
|
||||
* 导致永不重试(重试饥饿)
|
||||
* 2. N-32 §10:替代此前散落在 net_socket.c 各处的 net_relisten_try()
|
||||
* 返回值:无
|
||||
* 限定条件:netTask 上下文(API 路径与自愈 tick 内)
|
||||
* 函数说明:1. **取代原 net_listener_try**:try 是"当场动作",于是每个调用点都得
|
||||
* 自带状态门(U12 事故正是四处各防各的、漏一处就把活监听拆掉);
|
||||
* request 只置意图,门集与"芯片在听就不许 open"收进 net_listener_tick
|
||||
* 2. 已在请求中:不动重试时刻 —— 否则 10ms 一次的 accept 轮询会不断把
|
||||
* 重试时刻往后推 → 永不重试(重试饥饿,原 try 的同名防护保留)
|
||||
* 3. 非阻塞:实际重建发生在下一轮 net_listener_tick(≤1ms)
|
||||
* 4. 越界 sockfd 静默忽略(无返回值,不设错误码)
|
||||
*/
|
||||
int net_listener_try(int sockfd) {
|
||||
/* 当前 tick */
|
||||
uint32_t now = HAL_GetTick();
|
||||
|
||||
/* 描述符越界 → BADF */
|
||||
void net_listener_request(int sockfd, net_listener_req_t reason) {
|
||||
/* 描述符越界:静默忽略 */
|
||||
if ((sockfd < 0) || (sockfd >= NET_MAX_SOCKETS)) {
|
||||
return NET_ERR_RETURN_1(NET_ERR_BADF);
|
||||
return;
|
||||
}
|
||||
/* 已在重试队列:不重复尝试、不重置时刻(防重试饥饿) */
|
||||
if (s_relisten_wait[sockfd] != 0U) {
|
||||
(void)net_set_errno(NET_ERR_BUSY);
|
||||
/* 已在重试队列:由 tick 负责 */
|
||||
return -1;
|
||||
/* 已在请求中:保持既有节奏,不重置(防重试饥饿) */
|
||||
if (s_relisten_req[sockfd] != 0U) {
|
||||
return;
|
||||
}
|
||||
#if defined(TEST_LATENCY_PROBE)
|
||||
/* 恢复计时自首次尝试起 */
|
||||
lat_mark(&s_relisten_mark[sockfd]);
|
||||
#endif
|
||||
/* 本次尝试成功 */
|
||||
if (net_relisten_locked(sockfd) == 0) {
|
||||
/* 标记完成(清状态 + 探针样本) */
|
||||
net_relisten_done(sockfd);
|
||||
/* 监听器已就绪 */
|
||||
return 0;
|
||||
}
|
||||
/* 登记"待重试" */
|
||||
s_relisten_wait[sockfd] = 1U;
|
||||
/* 下次重试时刻 = now + 30ms */
|
||||
s_relisten_next[sockfd] = now + NET_RELISTEN_RETRY_MS;
|
||||
/* 放弃时刻 = now + 2s */
|
||||
s_relisten_dead[sockfd] = now + NET_RELISTEN_DEADLINE_MS;
|
||||
/* 本次失败(重试交 tick) */
|
||||
return -1;
|
||||
/* 登记来源(+1:0 保留给"无请求") */
|
||||
s_relisten_req[sockfd] = (uint8_t)((uint8_t)reason + 1U);
|
||||
/* 立即尝试(下一轮 tick);放弃时限自首次尝试起算,故此处清零 */
|
||||
s_relisten_next[sockfd] = 0U;
|
||||
s_relisten_dead[sockfd] = 0U;
|
||||
}
|
||||
|
||||
/*
|
||||
* 函数功能:D10 重试轮询(netTask 每轮调用一次,非阻塞)
|
||||
* 函数功能:监听重建的**唯一执行者**(netTask 每轮调用一次,非阻塞)
|
||||
* 入口参数:无
|
||||
* 出口参数:无
|
||||
* 返回值:无
|
||||
* 限定条件:netTask 上下文(由 net_process_messages 每轮调用)
|
||||
* 函数说明:1. 到点重试待办的重监听;成功即报告探针样本
|
||||
* 2. 本 fd 有在途挂起 recv / 挂起 send 时跳过(net_pending_active /
|
||||
* net_send_pending_active,挂起保险:重开 Socket 会摧毁在途传输)
|
||||
* 3. 超过 NET_RELISTEN_DEADLINE_MS 停止 D10 快速重试并留痕
|
||||
* (监听不永久失效——reconciler 100ms 周期仍按"芯片不在听"认领重建)
|
||||
* 函数说明:1. 遍历已登记请求的 fd,过**一处**门集后执行 open+listen;原名
|
||||
* net_listener_retry_tick(只做 D10 到点重试),现在它是唯一执行路径
|
||||
* 2. 门集(此前散在 4 个调用点,各防各的):控制块有效 + in_use +
|
||||
* 状态 ∈ {LISTENING, CLOSED}(0-4 口径:已转 ESTABLISHED = 新会话抢先,
|
||||
* 继续跑会 open→close 摧毁活连接)+ 监听型(auto_relisten / STREAM /
|
||||
* local_port≠0,与原 pump 认领口径一致)
|
||||
* 3. **芯片已在 LISTEN = 请求已达成,静默了结、绝不发 open**:U12 事故
|
||||
* (对在听新 SYN 的 Socket 再 open → 返 USE → 失败分支 close → 当场
|
||||
* 拆掉活监听)的结构性防护;读驱动状态缓存(net_poll 每轮刷新),零 SPI
|
||||
* 4. 挂起保险:本 fd 有在途挂起 recv / send 时跳过(重开 Socket 会摧毁
|
||||
* 在途传输,net_pending_active / net_send_pending_active)
|
||||
* 5. 节奏 30ms / 预算 2s(自首次尝试起);超预算清登记并留痕——监听不会
|
||||
* 永久失效,reconciler 100ms 周期仍按"芯片不在听"重新登记(形态③④)
|
||||
*/
|
||||
void net_listener_retry_tick(void) {
|
||||
void net_listener_tick(void) {
|
||||
/* 当前 tick */
|
||||
uint32_t now = HAL_GetTick();
|
||||
/* Socket 循环索引 */
|
||||
int i;
|
||||
/* 登记来源名(留痕分辨是谁登记的;与 net_listener_req_t 同序) */
|
||||
static const char *const k_req_name[] = { "recon", "accept", "eof", "drop", "pending" };
|
||||
|
||||
for (i = 0; i < NET_MAX_SOCKETS; i++) {
|
||||
/* 本 fd 无待重试重监听:跳过 */
|
||||
if (s_relisten_wait[i] == 0U) {
|
||||
/* 本 fd 无重建请求:跳过 */
|
||||
if (s_relisten_req[i] == 0U) {
|
||||
continue;
|
||||
}
|
||||
/* 0-4(自愈收敛阶段0)状态门:仅本层仍 LISTENING/CLOSED 才重试。若已转
|
||||
* ESTABLISHED(新会话抢先到达),在途重试登记即陈旧——继续跑会
|
||||
* open→close 摧毁活连接(认领口径与 reconciler 形态③④ 一致) */
|
||||
/* --- 门集:不满足即"登记已陈旧",清掉让位 --- */
|
||||
{
|
||||
/* 取控制块 */
|
||||
const net_sock_t *p_sock = net_get_sock(i);
|
||||
if ((p_sock == NULL) ||
|
||||
/* 控制块失效 / 未在用 / 状态不允许 / 非监听型 fd:陈旧登记 */
|
||||
if ((p_sock == NULL) || (p_sock->in_use == 0U) ||
|
||||
((p_sock->state != NET_SOCK_STATE_LISTENING) &&
|
||||
(p_sock->state != NET_SOCK_STATE_CLOSED))) {
|
||||
/* 陈旧登记:清重试状态让位 */
|
||||
(p_sock->state != NET_SOCK_STATE_CLOSED)) ||
|
||||
(p_sock->auto_relisten == 0U) ||
|
||||
(p_sock->type != NET_SOCK_STREAM) ||
|
||||
(p_sock->local_port == 0U)) {
|
||||
/* 陈旧登记:清状态让位 */
|
||||
net_listener_clear(i);
|
||||
continue;
|
||||
}
|
||||
/* 芯片已在听:请求已达成(见函数说明 3),静默了结 */
|
||||
{
|
||||
ch395f_sock_state_t c = ch395f_sock_state_cached((uint8_t)i);
|
||||
if ((c.open != CH395F_SOCKET_CLOSED) &&
|
||||
(c.tcp_state == CH395F_TCP_LISTEN)) {
|
||||
net_listener_clear(i);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* 本 fd 有在途挂起 recv / 挂起 send:重开 Socket 会摧毁在途连接(挂起保险) */
|
||||
if ((net_pending_active(i) != 0U) || (net_send_pending_active(i) != 0U)) {
|
||||
continue;
|
||||
}
|
||||
/* 未到点(tick 差值按有符号比较,抗回绕) */
|
||||
if ((int32_t)(now - s_relisten_next[i]) < 0) {
|
||||
/* 未到点(tick 差值按有符号比较,抗回绕;0 = 立即尝试) */
|
||||
if ((s_relisten_next[i] != 0U) && ((int32_t)(now - s_relisten_next[i]) < 0)) {
|
||||
continue;
|
||||
}
|
||||
/* 已到放弃时限 */
|
||||
if ((int32_t)(now - s_relisten_dead[i]) >= 0) {
|
||||
/* 已到放弃时限(0 = 尚未起算,见下) */
|
||||
if ((s_relisten_dead[i] != 0U) && ((int32_t)(now - s_relisten_dead[i]) >= 0)) {
|
||||
/* 清重试状态 */
|
||||
net_listener_clear(i);
|
||||
/* D10 快速重试预算耗尽留痕:后续交 reconciler 形态③④ 周期接管
|
||||
@@ -448,14 +482,26 @@ void net_listener_retry_tick(void) {
|
||||
DBG_ERROR("sock%d relisten retry budget exhausted, reconciler takes over", i);
|
||||
continue;
|
||||
}
|
||||
/* 重试成功 */
|
||||
/* 首次尝试:起算放弃时限与恢复计时起点 */
|
||||
if (s_relisten_dead[i] == 0U) {
|
||||
s_relisten_dead[i] = now + NET_RELISTEN_DEADLINE_MS;
|
||||
#if defined(TEST_LATENCY_PROBE)
|
||||
/* 恢复计时自首次尝试起 */
|
||||
lat_mark(&s_relisten_mark[i]);
|
||||
#endif
|
||||
}
|
||||
/* 执行一次重建(本函数是 net_relisten_locked 的唯一调用者) */
|
||||
if (net_relisten_locked(i) == 0) {
|
||||
/* 登记来源名(越界兜底:枚举扩充时不得越界读) */
|
||||
uint8_t idx = (uint8_t)(s_relisten_req[i] - 1U);
|
||||
const char *name = (idx < (uint8_t)(sizeof(k_req_name) / sizeof(k_req_name[0])))
|
||||
? k_req_name[idx] : "?";
|
||||
/* 留痕:监听器重建完成(带登记来源;成功留痕已从 net_relisten_locked 收并到此一处) */
|
||||
DBG_INFO("sock%d auto-relisten ok (%s)", i, name);
|
||||
/* 标记完成(清状态 + 探针样本) */
|
||||
net_relisten_done(i);
|
||||
/* 留痕:重试成功 */
|
||||
DBG_INFO("sock%d relisten retry ok", i);
|
||||
} else {
|
||||
/* 仍未成:置下次重试时刻 */
|
||||
/* 仍未成:顺延 30ms 再来 */
|
||||
s_relisten_next[i] = now + NET_RELISTEN_RETRY_MS;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,13 +2,17 @@
|
||||
* 模块名称:Network Listener Lifecycle (Header)
|
||||
* 模块功能:监听器生命周期模块的对外接口(**真机专属**)—— 维持 fd 处于
|
||||
* LISTEN 态的全部机制:重建、重建前的沉降/隔离(TRAP-NET-18)、排空 RX
|
||||
* 残渣、D10 非阻塞重试(周期重建决策者=自愈收敛阶段 3 合并后的
|
||||
* net_reconcile_tick,见 net_socket.c)。
|
||||
* 残渣、D10 非阻塞重试。**本模块是"把 fd 放回 LISTEN"的唯一执行者**:
|
||||
* 外部只登记请求(net_listener_request),动作只在 net_listener_tick 一处发生;
|
||||
* "该不该重建"的周期判据仍在 net_reconcile_tick(形态③④,见 net_socket.c)。
|
||||
* 适用平台:STM32F407ZGTx + CH395F 以太网芯片
|
||||
* 作者:王建锋
|
||||
* 创建日期:2026-10-12
|
||||
* 修改记录:
|
||||
* 2026-10-12 王建锋 从 net_socket.c 抽出监听生命周期(N-32 §10 模块化)
|
||||
* 2026-10-14 王建锋 单一所有者收口:net_listener_try(各调用点自带门、当场动作)
|
||||
* 改为 net_listener_request(只登记意图)+ net_listener_tick
|
||||
* (唯一执行者,门集与芯片在听判据集中一处)
|
||||
*
|
||||
* 职责边界(详见 docs/网络/网络自愈架构设计.md §11):
|
||||
* 本模块只负责「让一个监听型 fd 保持/回到 LISTEN 态」。
|
||||
@@ -47,24 +51,38 @@ typedef enum {
|
||||
* 出口参数:无
|
||||
* 返回值:无
|
||||
* 限定条件:netTask 上下文;由 handle_disconnect_event / handle_timeout_event 调用
|
||||
* 函数说明:1. 只置事实,不做动作 —— 重建由 net_reconcile_tick(形态③④)/
|
||||
* net_listener_try 负责
|
||||
* 函数说明:1. 只置事实,不做动作 —— 动作只在 net_listener_tick 一处发生
|
||||
* 2. 越界 sockfd 静默忽略(不设错误码)
|
||||
*/
|
||||
void net_listener_settle(int sockfd, net_listener_settle_t level);
|
||||
|
||||
/*
|
||||
* 函数功能:尝试重建监听一次(**不阻塞**);失败则登记"待重试"
|
||||
* 入口参数:sockfd - Socket 描述符 (0~7) int
|
||||
* 出口参数:无
|
||||
* 返回值:0 - 成功(监听器已就绪);-1 - 本次失败或已在重试队列中 int
|
||||
* 限定条件:netTask 上下文;fd 为监听型(auto_relisten)
|
||||
* 函数说明:1. 已在重试队列时直接返回 -1(不重复尝试、不重置重试时刻)——
|
||||
* 否则每 10 ms 一次的 accept 轮询会不断把重试时刻往后推,
|
||||
* 导致永不重试(重试饥饿)
|
||||
* 2. 替代此前散落在 net_socket.c 各处的 net_relisten_try()
|
||||
* 重建请求来源:只用于留痕归因(日志里分辨是谁登记的),不改变动作
|
||||
* —— 单一所有者的意义正在于此:来源再多,执行只有一条路径、一套门
|
||||
*/
|
||||
int net_listener_try(int sockfd);
|
||||
typedef enum {
|
||||
NET_LISTENER_REQ_RECON = 0U, /* 对账形态③④:芯片侧监听失位 / 孤儿监听 */
|
||||
NET_LISTENER_REQ_ACCEPT = 1U, /* 消费者 accept 撞上 CLOSED 的监听 fd */
|
||||
NET_LISTENER_REQ_EOF = 2U, /* 消费者 recv 读到 EOF */
|
||||
NET_LISTENER_REQ_DROP = 3U, /* net_drop_conn 拆会话保监听 */
|
||||
NET_LISTENER_REQ_PENDING = 4U, /* 挂起 recv 因断连结束 */
|
||||
} net_listener_req_t;
|
||||
|
||||
/*
|
||||
* 函数功能:登记「本 fd 期望回到 LISTEN」(**只登记意图,不碰芯片**)
|
||||
* 入口参数:sockfd - Socket 描述符 (0~7) int
|
||||
* reason - 登记来源(net_listener_req_t,仅留痕归因)
|
||||
* 出口参数:无
|
||||
* 返回值:无
|
||||
* 限定条件:netTask 上下文(API 路径与自愈 tick 内)
|
||||
* 函数说明:1. **取代原 net_listener_try**:try 是"当场动作",故每个调用点都得
|
||||
* 自带状态门(U12 事故就是这么四处各防各的);request 只置意图,
|
||||
* 门集与"芯片已在听就不许再 open"的判据收进 net_listener_tick 一处
|
||||
* 2. 已在请求中时**不动重试时刻**:否则 10ms 一次的 accept 轮询会把
|
||||
* 重试时刻不断往后推 → 永不重试(重试饥饿,原 try 的同名防护保留)
|
||||
* 3. 非阻塞:实际重建在下一轮 net_listener_tick(≤1ms)里做
|
||||
*/
|
||||
void net_listener_request(int sockfd, net_listener_req_t reason);
|
||||
|
||||
/*
|
||||
* 函数功能:清除本 fd 的待重试/沉降状态(关闭或新建 fd 时调用)
|
||||
@@ -77,18 +95,29 @@ int net_listener_try(int sockfd);
|
||||
void net_listener_clear(int sockfd);
|
||||
|
||||
/*
|
||||
* 函数功能:D10 重试轮询(netTask 每轮调用,非阻塞)
|
||||
* 函数功能:监听重建的**唯一执行者**(netTask 每轮调用,非阻塞)
|
||||
* 入口参数:无
|
||||
* 出口参数:无
|
||||
* 返回值:无
|
||||
* 限定条件:netTask 上下文(由 net_process_messages 每轮调用)
|
||||
* 函数说明:到点重试待办的重监听;成功即报告探针样本;超时放弃并记错误日志
|
||||
* 函数说明:1. 遍历已登记请求的 fd,按**一处**门集裁决后执行 open+listen:
|
||||
* 控制块有效 + in_use + 状态 ∈ {LISTENING, CLOSED} + 监听型
|
||||
* (auto_relisten / STREAM / local_port≠0)+ 无在途挂起 recv/send
|
||||
* + 到点(30ms 节奏)+ 未超预算(2s)
|
||||
* 2. **芯片已在 LISTEN 即视为请求已达成**(读驱动状态缓存,零 SPI)——
|
||||
* 这是 U12 事故的结构性防护:绝不对正在听新 SYN 的 Socket 再 open
|
||||
* (旧形态下 open 返 USE → 失败分支 close → 当场拆掉活监听)
|
||||
* 3. 原名 net_listener_retry_tick(只做 D10 到点重试);现在它是唯一
|
||||
* 执行路径,故按同族 tick 命名(net_pending_tick / net_reconcile_tick)
|
||||
* 4. 超预算清登记并 [ERR] 留痕:监听不会永久失效——reconciler 100ms
|
||||
* 周期仍会按"芯片不在听"重新登记(形态③④)
|
||||
*/
|
||||
void net_listener_retry_tick(void);
|
||||
void net_listener_tick(void);
|
||||
|
||||
/* 自愈收敛阶段 3:原 `net_listener_pump`(周期重建决策者)已并入 net_socket.c 的
|
||||
* net_reconcile_tick 单一 100ms tick(判据读驱动状态缓存,《网络自愈架构设计》§4.1)。
|
||||
* 本模块的 net_listener_try 由 reconciler 形态③④ 与 D10 重试轮询调用。 */
|
||||
* 本模块的 net_listener_tick 是执行者,登记方 = reconciler 形态③④ + 各消费者路径
|
||||
* (accept / recv EOF / drop_conn / 挂起 recv 断连),全部走 net_listener_request。 */
|
||||
|
||||
/* 注:本模块消费的宿主能力 `net_pending_active()` / `net_send_pending_active()`
|
||||
* 声明在 net_pending.h(它们是 net_pending.c 的函数,须与配对头文件同处,
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
* net_types.h(net_sock_t / NET_ERR_* / NET_SOCK_STATE_*)/
|
||||
* net_socket.h(NET_MAX_SOCKETS / net_set_errno / NET_ERR_RETURN_1 /
|
||||
* net_pending_active 声明)/ net_pending.h(本模块接口)/
|
||||
* net_listener.h(net_listener_try)/ ch395f.h(RX 读出 / TX 分块写)/ main.h(HAL_GetTick)
|
||||
* net_listener.h(net_listener_request / net_listener_tick)/ ch395f.h(RX 读出 / TX 分块写)/ main.h(HAL_GetTick)
|
||||
* 限定条件:本文件真机专属——模拟器走 sim/net_socket_sim.c,
|
||||
* simulator/CMakeLists.txt 不编译本文件(同 net_listener.c 先例)
|
||||
*
|
||||
@@ -255,17 +255,16 @@ void net_pending_tick(net_sock_t *p_socks) {
|
||||
/* 结束:以字节数通知 */
|
||||
net_pending_complete(i, rd);
|
||||
} else {
|
||||
/* 启用自动重监听:先把监听器重新置回 LISTEN。
|
||||
* ⚠ 内层 `state == CLOSED` 门同 net_recv_locked:session_dead
|
||||
* 但已回 LISTENING 时重建已由别处完成,再 open+listen 会因
|
||||
* USE 错误走进关闭分支、关掉正听着的 Socket(U12 同源)。
|
||||
* N-32 P2 修正:**保留本处即时重建** —— 它只在有**挂起 recv**
|
||||
/* 启用自动重监听:登记重建请求(动作在 net_listener_tick 一处)。
|
||||
* 原内层 `state == CLOSED` 门已**上收到 tick**——它防的是"对已回
|
||||
* LISTENING 的 fd 再 open+listen → 因 USE 错误走进关闭分支、关掉
|
||||
* 正听着的 Socket"(U12 同源),属执行侧安全不变量,不由登记点复述。
|
||||
* N-32 P2 修正:**保留本处即时登记** —— 它只在有**挂起 recv**
|
||||
* 时到达(`p->active != 0`),属"消费者在等这条连接结局"的
|
||||
* 消费者驱动路径,不是周期性抢先(同 net_recv_locked 的理由)。 */
|
||||
if ((p_sock->state == NET_SOCK_STATE_CLOSED) &&
|
||||
(p_sock->auto_relisten != 0U)) {
|
||||
/* 非阻塞:失败由 D10 重试轮询接管(N-32 §10:入口收敛到 net_listener_try) */
|
||||
(void)net_listener_try(i);
|
||||
if (p_sock->auto_relisten != 0U) {
|
||||
/* 非阻塞:下一轮 net_listener_tick 执行(入口收敛到 request) */
|
||||
net_listener_request(i, NET_LISTENER_REQ_PENDING);
|
||||
}
|
||||
/* TRAP-NET-18 待办 #3:异常释放(TIMEOUT/RST)不是正常 EOF(对端未发正常 FIN)
|
||||
* → 按连接重置结束:应用(lftpd STOR)对异常结束回 5xx 而非误报 226;
|
||||
@@ -313,7 +312,7 @@ void net_pending_tick(net_sock_t *p_socks) {
|
||||
* 出口参数:无
|
||||
* 返回值:1 - 有挂起;0 - 无(含描述符越界) int
|
||||
* 限定条件:任意上下文(纯 RAM 读,不发起 RPC)
|
||||
* 函数说明:1. N-32 §10 模块化:net_listener_retry_tick 用它跳过"重开 Socket
|
||||
* 函数说明:1. N-32 §10 模块化:net_listener_tick 用它跳过"重开 Socket
|
||||
* 会摧毁在途连接"的 fd(挂起 recv 保险,原为直接读 s_net_pending[i].active)
|
||||
* 2. 声明在 net_pending.h(配对头,规范 S17 2.2)
|
||||
*/
|
||||
@@ -675,7 +674,7 @@ void net_send_pending_cancel_all(int err) {
|
||||
* 出口参数:无
|
||||
* 返回值:1 - 有挂起;0 - 无(含描述符越界) int
|
||||
* 限定条件:任意上下文(纯 RAM 读,不发起 RPC)
|
||||
* 函数说明:net_listener_retry_tick 用它跳过"重开 Socket 会摧毁在途传输"的 fd
|
||||
* 函数说明:net_listener_tick 用它跳过"重开 Socket 会摧毁在途传输"的 fd
|
||||
* (挂起 send 保险;与 net_pending_active 的挂起 recv 保险并列)
|
||||
*/
|
||||
int net_send_pending_active(int sockfd) {
|
||||
|
||||
@@ -123,7 +123,7 @@ void net_pending_settle_close(int sockfd, net_sock_t *p_sock);
|
||||
* 出口参数:无
|
||||
* 返回值:1 - 有挂起;0 - 无(含描述符越界) int
|
||||
* 限定条件:任意上下文(纯 RAM 读,不发起 RPC)
|
||||
* 函数说明:N-32 §10 模块化:net_listener_retry_tick 用它跳过"重开 Socket
|
||||
* 函数说明:N-32 §10 模块化:net_listener_tick 用它跳过"重开 Socket
|
||||
* 会摧毁在途连接"的 fd(挂起 recv 保险)
|
||||
*/
|
||||
int net_pending_active(int sockfd);
|
||||
@@ -207,7 +207,7 @@ void net_send_pending_cancel_all(int err);
|
||||
* 出口参数:无
|
||||
* 返回值:1 - 有挂起;0 - 无(含描述符越界) int
|
||||
* 限定条件:任意上下文(纯 RAM 读,不发起 RPC)
|
||||
* 函数说明:与 net_pending_active 同用途——net_listener_retry_tick 据此跳过
|
||||
* 函数说明:与 net_pending_active 同用途——net_listener_tick 据此跳过
|
||||
* "重开 Socket 会摧毁在途传输"的 fd(挂起 send 保险)
|
||||
*/
|
||||
int net_send_pending_active(int sockfd);
|
||||
|
||||
@@ -780,11 +780,11 @@ static void net_reconcile_tick(void) {
|
||||
/* 挂起 send 同样取消(会话已被芯片收走,剩余字节不可能送达) */
|
||||
net_send_pending_cancel(i, NET_ERR_CONNRESET);
|
||||
} else if ((bad == 3) || (bad == 4)) {
|
||||
/* 类型③④:监听失位/孤儿监听 → 重建(本层唯一重建入口;
|
||||
* 非阻塞:失败由 D10 重试轮询接管) */
|
||||
/* 类型③④:监听失位/孤儿监听 → **登记**重建请求(判据在此,动作在
|
||||
* net_listener_tick 一处;非阻塞,30ms 节奏重试) */
|
||||
DBG_INFO("sock%d reconcile: chip not listening (0x%02X/0x%02X, was state=%d) -> relisten",
|
||||
i, c.open, c.tcp_state, (int)p_sock->state);
|
||||
(void)net_listener_try(i);
|
||||
net_listener_request(i, NET_LISTENER_REQ_RECON);
|
||||
} else {
|
||||
/* 类型②:补做 standalone accept */
|
||||
DBG_INFO("sock%d reconcile: connection completed w/o CONNECT irq -> accept", i);
|
||||
@@ -806,8 +806,8 @@ static void net_reconcile_tick(void) {
|
||||
* 限定条件:必须在 netTask 上下文中调用(独占 CH395F 与 s_net_socks 访问权);
|
||||
* 由 net_task.c 在 net_stack_bring_up 之后每次 1ms 循环调用。
|
||||
* 函数说明:1. 四个自愈 tick 均非阻塞(绝不 osDelay 忙等,netTask 永不冻结),先于消息分派执行
|
||||
* 2. net_listener_retry_tick(D10):断连后按 30ms 节拍重试 open+listen,
|
||||
* 2s 时限到期放弃留痕;本 fd 有在途挂起 recv / send 时跳过(挂起保险)
|
||||
* 2. net_listener_tick(监听重建**唯一执行者**):消费各路径登记的请求,
|
||||
* 30ms 节奏 / 2s 预算;门集与"芯片在听就不 open"(U12 防护)都在这一处
|
||||
* 3. net_pending_tick:按节拍结束挂起 recv(数据/到点[仅显式预算]/断连)
|
||||
* 4. net_send_pending_tick:按节拍推进挂起 send(断连/推进/写完/无进展超时)
|
||||
* 5. net_reconcile_tick(TRAP-NET-17 + pump 合并,自愈收敛阶段 3):100ms 对账
|
||||
@@ -825,8 +825,8 @@ void net_process_messages(void) {
|
||||
}
|
||||
|
||||
/* 四个非阻塞自愈 tick 置于消息处理之前:断连后即使无应用消息,监听器也能自主恢复 */
|
||||
/* D10 重监听重试(TRAP-NET-09):沉降后重开芯片监听器 */
|
||||
net_listener_retry_tick();
|
||||
/* 监听重建唯一执行者(TRAP-NET-09 D10 节奏;消费各路径登记的请求) */
|
||||
net_listener_tick();
|
||||
/* 挂起 recv 完成检查:数据到达 / 到点 / 断连时通知调用方 */
|
||||
net_pending_tick(s_net_socks);
|
||||
/* 挂起 send 推进与完成检查(SEND pending):断连 / 推进写块 / 写完 / 无进展超时 */
|
||||
@@ -1516,13 +1516,13 @@ static int net_accept_locked(int sockfd, struct net_sockaddr *addr, int *addrlen
|
||||
drain_pending = 1;
|
||||
DBG_INFO("sock%d closed-with-data accept (drain pending)", sockfd);
|
||||
} else {
|
||||
/* 连接已断开(CLOSED)且无残留数据:先把 Socket 重新置回 LISTEN,
|
||||
* 下一次 accept 即可等待新连接(BSD 风格监听常驻)。
|
||||
* N-32 P2 修正:**保留本处即时重建** —— 它由消费者调 accept 触发
|
||||
/* 连接已断开(CLOSED)且无残留数据:登记重建请求,下一次 accept
|
||||
* 即可等待新连接(BSD 风格监听常驻)。
|
||||
* N-32 P2 修正:**保留本处即时登记** —— 它由消费者调 accept 触发
|
||||
* (消费者正在等新连接),不是周期性抢先;删掉会把 CLOSED 窗口
|
||||
* 拉长、导致调用方高频空转 accept(实测 [WD] task stall)。
|
||||
* 非阻塞:失败由 D10 重试轮询接管 */
|
||||
(void)net_listener_try(sockfd);
|
||||
* 单一所有者收口后:动作发生在下一轮 net_listener_tick(≤1ms),非阻塞 */
|
||||
net_listener_request(sockfd, NET_LISTENER_REQ_ACCEPT);
|
||||
}
|
||||
}
|
||||
if (drain_pending == 0) {
|
||||
@@ -2155,20 +2155,20 @@ static int net_recv_locked(net_sock_t *p_sock, void *buf, int len, int flags,
|
||||
* 有数据时走上方快路径(recv_len>0 优先),本判据只在"无数据"时生效,
|
||||
* 故不会把新连接的起始数据误判为 EOF。 */
|
||||
if ((p_sock->state == NET_SOCK_STATE_CLOSED) || (p_sock->session_dead != 0U)) {
|
||||
/* 启用自动重监听:先把监听器重新置回 LISTEN。
|
||||
* ⚠ 内层 `state == CLOSED` 门是**必需的**,不是冗余:
|
||||
* `net_listener_try` 无状态门,对已 LISTENING 的 fd 再 open+listen
|
||||
* 会让 ch395f_open_socket 返 USE,其失败分支会 ch395f_close_socket
|
||||
* —— 把正听着新 SYN 的 Socket 当场关掉(U12 同源事故)。
|
||||
* session_dead + 已回 LISTENING = 重建已由别处完成,这里只报 EOF。
|
||||
* N-32 P2 修正(2026-10-12 台架实证):**保留本处即时重建**。
|
||||
/* 启用自动重监听:登记重建请求(动作在 net_listener_tick 一处)。
|
||||
* ⚠ 原此处内层 `state == CLOSED` 门已**上收到 tick**:它防的是"对已
|
||||
* LISTENING 的 fd 再 open+listen → ch395f_open_socket 返 USE → 失败分支
|
||||
* ch395f_close_socket → 把正听着新 SYN 的 Socket 当场关掉"(U12 同源
|
||||
* 事故)。这是**执行侧安全不变量**,不该由每个登记点各自复述——
|
||||
* 漏一处即事故;收口后 tick 另加"芯片已在听即了结",结构上不可能再犯。
|
||||
* N-32 P2 修正(2026-10-12 台架实证):**保留本处即时登记**——
|
||||
* 它是"消费者动作触发"(消费者正在等这条连接的结局),不是周期性
|
||||
* "抢先";删掉它会把 CLOSED 窗口从 ~0 拉长到 pump 周期+隔离期
|
||||
* "抢先";删掉它会把 CLOSED 窗口从 ~0 拉长到 reconciler 周期+隔离期
|
||||
* (~100ms),期间调用方高频发起 net_accept(RPC 无上界)→
|
||||
* `[WD] task stall`(实测 uis 往返 1063ms)。周期性抢先由 reconciler 收敛即可。 */
|
||||
if ((p_sock->state == NET_SOCK_STATE_CLOSED) && (p_sock->auto_relisten != 0U)) {
|
||||
/* 非阻塞:失败由 D10 重试轮询接管 */
|
||||
(void)net_listener_try(sockfd);
|
||||
* `[WD] task stall`(实测 uis 往返 1063ms)。周期性兜底由 reconciler 收敛。 */
|
||||
if (p_sock->auto_relisten != 0U) {
|
||||
/* 非阻塞:下一轮 net_listener_tick 执行,30ms 节奏重试 */
|
||||
net_listener_request(sockfd, NET_LISTENER_REQ_EOF);
|
||||
}
|
||||
/* EOF:返回 0(非错误) */
|
||||
return 0;
|
||||
@@ -2247,9 +2247,10 @@ static int net_close_locked(net_sock_t *p_sock) {
|
||||
* "拆连接不拆监听"的应用侧形态
|
||||
* 2. 拆除=sock_reset QUARANTINE(TRAP-NET-18 异常释放语义:FIN + 排渣 +
|
||||
* 排空事件(quiescent) + 等 byte0=00H,内置二段 CLOSE 补发)
|
||||
* 3. auto_relisten(监听型 fd):收口 CLOSED 后即时 net_listener_try
|
||||
* (芯片已 CLOSED 直接 open 必成,E4 定案;失败交 D10 重试 +
|
||||
* reconciler 形态④);非 auto_relisten(client fd):收口 CLOSED,
|
||||
* 3. auto_relisten(监听型 fd):收口 CLOSED 后登记重建请求(动作在
|
||||
* net_listener_tick,≤1ms 后执行;芯片已 CLOSED 直接 open 必成,
|
||||
* E4 定案;未成则 30ms 节奏重试 + reconciler 形态④兜底);
|
||||
* 非 auto_relisten(client fd):收口 CLOSED,
|
||||
* 是否重连由调用方决定
|
||||
* 4. 挂起 recv 先结束(settle_close:排空尝试或取消,必通知)
|
||||
*/
|
||||
@@ -2275,8 +2276,8 @@ static int net_drop_conn_locked(net_sock_t *p_sock) {
|
||||
p_sock->lost_conn_seen = 0U;
|
||||
|
||||
if (p_sock->auto_relisten) {
|
||||
/* 监听型 fd:即时重建(非阻塞;失败 D10 重试轮询接管) */
|
||||
(void)net_listener_try(sockfd);
|
||||
/* 监听型 fd:登记重建请求(非阻塞;下一轮 net_listener_tick 执行) */
|
||||
net_listener_request(sockfd, NET_LISTENER_REQ_DROP);
|
||||
}
|
||||
|
||||
/* 拆除完成 */
|
||||
|
||||
Reference in New Issue
Block a user