net_socket.c补net_process_messages分派文档:三个自愈tick机制、各消息类型处理说明与结果回传路径

This commit is contained in:
2026-09-24 22:49:15 +08:00
parent f4281fb370
commit 86e261d6df
+85 -5
View File
@@ -496,10 +496,26 @@ static void net_reconcile_tick(void) {
} }
/* /*
* 函数功能:处理消息队列中的请求 * 函数功能:netTask 主循环核心 —— 自愈 tick 宿主 + 消息队列分派器。每轮
* 限定条件:必须在 netTask 上下文中调用(独占 CH395F 和 s_net_socks 访问权) * 先跑三个非阻塞自愈 tick(D10 重监听 / L3 挂起 recv / Trap 22
* 函数说明:每次调用处理一条消息。处理 send/recv 时内部会调用 net_poll() * 状态对账),再非阻塞排空队列按 msg.type 分派到 _locked 实现。
* 等待操作完成。处理完毕后通知调用方任务。 * 限定条件:必须在 netTask 上下文中调用(独占 CH395F 与 s_net_socks 访问权);
* 由 net_task.c 在 net_stack_bring_up 之后每次 1ms 循环调用。
* 返回值 :void;结果经 xTaskNotify 通知值回传(成功=字节数/描述符,
* 失败=具体错误码);调用方 net_wait_result 拾取,对外统一 -1。
* 函数说明:
* ① 三个自愈 tick 均非阻塞(绝不 osDelay 忙等,netTask 永不冻结):
* - net_relisten_retry_tick(D10):断连后按 30ms(NET_RELISTEN_RETRY_MS)
* 节拍重试 open+listen,2s(NET_RELISTEN_DEADLINE_MS)总时限到期放弃留痕;
* 本 fd 有在途挂起 recv 时跳过(L3 保险)。
* - net_pending_tick(L3):按节拍了结挂起 recv(①数据 ②到点 ③断连);
* 到点后 1s(NET_PENDING_WATCHDOG_MS)未了结 → 强制了结 + DBG_ERROR 留痕。
* - net_reconcile_tick(Trap 22):每 200ms(NET_RECONCILE_PERIOD_MS)对账,
* 连续 2 次失配去抖 + 1s 冷却,三类失同步自愈。
* ② net_msg_t 按值入队,netTask 侧副本调用方不可见 → 结果只能搭
* 任务通知值回传;32 位整体即结果,不做位域压缩。
* ③ RECV 特例:无数据+阻塞 → 登记 pending 哨兵 NET_PENDING_REGISTERED
* (0x70000000),do_notify=0,回执推迟到 net_pending_tick 完成时。
*/ */
void net_process_messages(void) { void net_process_messages(void) {
net_msg_t msg; net_msg_t msg;
@@ -515,11 +531,25 @@ void net_process_messages(void) {
net_pending_tick(); net_pending_tick();
net_reconcile_tick(); /* Trap 22:芯片/本层状态周期对账(丢中断自愈) */ net_reconcile_tick(); /* Trap 22:芯片/本层状态周期对账(丢中断自愈) */
/* 队列排空:超时 0 非阻塞取,直到本轮队列为空。do_notify=1 表示
* 本条消息需要即时回执;=0 只出现在 RECV 挂起登记(返回哨兵
* NET_PENDING_REGISTERED)——回执推迟到 net_pending_tick 完成检查
* 发出,避免把"登记成功"误当成处理结果通知调用方。 */
while (osMessageQueueGet(netMsgQueueHandle, &msg, NULL, 0) == osOK) { while (osMessageQueueGet(netMsgQueueHandle, &msg, NULL, 0) == osOK) {
int do_notify = 1; int do_notify = 1;
switch (msg.type) { switch (msg.type) {
case NET_MSG_SEND: { case NET_MSG_SEND: {
/* TCP send:由 net_send_locked 真正写 CH395F。
* - net_get_sock 返回 NULL(fd 越界/已 close)→ NET_ERR_BADF
* - 状态非 ESTABLISHED → NET_ERR_NOTCONN
* - 否则按硬件发送缓冲上限(NET_SEND_CHUNK_MAX=1KB)分块
* 写入并等待 send_ready(SEND_OK 中断),单块停滞
* NET_SEND_TIMEOUT_MS(1s) 超时;中途断连立即失败 CONNRESET
* (不白等满超时)。
* 返回实际写入字节数;短写会 DBG_ERROR 留痕,调用方须校验
* 返回值而非只看非负。成功=字节数、失败=-1(errno 随通知值
* 回传)。 */
net_sock_t *p_sock = net_get_sock(msg.sockfd); net_sock_t *p_sock = net_get_sock(msg.sockfd);
if (p_sock == NULL) { if (p_sock == NULL) {
s_net_errno = NET_ERR_BADF; s_net_errno = NET_ERR_BADF;
@@ -533,6 +563,21 @@ void net_process_messages(void) {
break; break;
} }
case NET_MSG_RECV: { case NET_MSG_RECV: {
/* TCP/UDP recv:由 net_recv_locked 走三条出口——
* ① 数据已就绪 → 快速 SPI 读出,返回字节数(即时回执);
* ② 无数据 + NET_MSG_DONTWAIT → CLOSED 态按对端关闭返回 0
* (触发 auto_relisten),否则 NET_ERR_WOULDBLOCK(-1)
* (即时回执);
* ③ 无数据 + 阻塞等待 → 登记挂起请求并返回哨兵
* NET_PENDING_REGISTERED(每 fd 至多一个,禁止覆盖——
* 覆盖会丢失前一次调用方的通知使其永久挂死;
* caller==NULL 或调用者本身是 netTask 时拒绝登记,
* 防"自等自通知"死锁):本条消息 do_notify=0 不发即时
* 回执,完成(数据/30s 默认超时或 msg.timeout_ms 指定
* 预算/断连/显式取消 close、resync、网络重建)由
* net_pending_tick 按主循环节拍以字节数/0/负错误码通知
* caller。挂起期间 msg.buf 指针须保持有效(net_pending
* 只存指针不拷贝数据)。 */
net_sock_t *p_sock = net_get_sock(msg.sockfd); net_sock_t *p_sock = net_get_sock(msg.sockfd);
if (p_sock == NULL) { if (p_sock == NULL) {
s_net_errno = NET_ERR_BADF; s_net_errno = NET_ERR_BADF;
@@ -549,6 +594,14 @@ void net_process_messages(void) {
break; break;
} }
case NET_MSG_CLOSE: { case NET_MSG_CLOSE: {
/* TCP close:先了结本 fd 的挂起 recv(排空可读数据或
* NET_ERR_CONNRESET 取消——必通知,防等待中调用方永久挂死),
* 再 ch395f_close_socket、轮询等芯片回 CLOSED(≤500ms)并
* 排空残留中断、memset 控制块、清 D10 待重试与 L3 挂起状态。
* fd 越界/已关闭 → NET_ERR_BADF;成功返回 0。
* 单连接模型注意:监听 fd 断开后 auto_relisten 会自动恢复
* 监听,EOF 时应用层**不要**对监听 fd 发 close(会毁掉端口
* → 连接永拒),仅独立数据 fd 才 close。 */
net_sock_t *p_sock = net_get_sock(msg.sockfd); net_sock_t *p_sock = net_get_sock(msg.sockfd);
if (p_sock == NULL) { if (p_sock == NULL) {
s_net_errno = NET_ERR_BADF; s_net_errno = NET_ERR_BADF;
@@ -559,16 +612,39 @@ void net_process_messages(void) {
break; break;
} }
case NET_MSG_CONNECT: { case NET_MSG_CONNECT: {
/* TCP connect(异步,返回成功即已下发 CONNECT 命令):保存
* 远端 IP/端口(msg.addr/addrlen 由公开 API net_connect 的
* memcpy 填入)→ open 失败 3 次重试(Trap 09,每次失败先
* close 再重试)→ 清本 Socket 残留中断(防上一条连接遗留
* DISCONNECT 误判)→ 下发 TCP CONNECT → 状态置 CONNECTING
* 等待 CONNECT 中断(net_poll 维护状态与事件)。失败 NET_ERR_BUSY/
* INVAL 返回 -1;成功返回 0,调用方须轮询 net_sock_state()
* 等 ESTABLISHED 后才是可用连接。 */
msg.result = net_connect_locked(msg.sockfd, msg.result = net_connect_locked(msg.sockfd,
(const struct net_sockaddr *)&msg.addr, (const struct net_sockaddr *)&msg.addr,
msg.addrlen); msg.addrlen);
break; break;
} }
case NET_MSG_LISTEN: { case NET_MSG_LISTEN: {
/* TCP listen:仅 BOUND/CREATED 态的 TCP 流 socket 允许。
* open+TCP_LISTEN 失败 3 次重试(Trap 09)→ 状态置
* LISTENING、auto_relisten=1、清各 Socket 及全局历史中断
*(防残留/伪中断在监听刚生效时误触发连接/断开事件)。成功
* 返回 0;失败 NET_ERR_INVAL/BUSY 返回 -1。单连接模型下该
* fd 后续即数据通道(g_client==g_listen),断开后自动重监听
*(模拟 BSD 监听常驻,应用层无需手动重建)。 */
msg.result = net_listen_locked(msg.sockfd); msg.result = net_listen_locked(msg.sockfd);
break; break;
} }
case NET_MSG_ACCEPT: { case NET_MSG_ACCEPT: {
/* accept:入参经 net_msg_t 的 buf/len 字段携带(公开 API
* net_accept 将 addr 指针与 addrlen 填入 msg.buf/msg.len;
* addrlen>0 且 buf 非 NULL 时,net_accept_locked 通过局部
* 变量指针回填对端地址长度 sizeof(net_sockaddr_in))。
* 单连接:状态 ESTABLISHED 即有可接受连接 → 返回同一 fd
*(监听 Socket 自身已转为数据通道);非 ESTABLISHED →
* CLOSED+auto_relisten 先非阻塞尝试恢复监听,最终
* NET_ERR_WOULDBLOCK(-1)。失败返回具体错误码。 */
struct net_sockaddr *p_addr = (struct net_sockaddr *)msg.buf; struct net_sockaddr *p_addr = (struct net_sockaddr *)msg.buf;
int addrlen = msg.len; int addrlen = msg.len;
int *p_addrlen = (p_addr != NULL && addrlen > 0) ? &addrlen : NULL; int *p_addrlen = (p_addr != NULL && addrlen > 0) ? &addrlen : NULL;
@@ -609,7 +685,11 @@ void net_process_messages(void) {
break; break;
} }
default: default:
s_net_errno = NET_ERR; /* 未知消息类型:置通用错误码,保证回传值有效 */ /* 未知消息类型(枚举闭合,正常不应触发):置通用错误码
* NET_ERR、结果 -1,保证通知值永远有效——调用方通过
* net_wait_result 拿到的是本条消息的确定结果,而非
* 上一条消息的残留值。 */
s_net_errno = NET_ERR;
msg.result = -1; msg.result = -1;
break; break;
} }