From 86e261d6df94be6db35ffd6d591f7998b75cd369 Mon Sep 17 00:00:00 2001 From: Wanderingss <1624155937@qq.com> Date: Thu, 24 Sep 2026 22:49:15 +0800 Subject: [PATCH] =?UTF-8?q?net=5Fsocket.c=E8=A1=A5net=5Fprocess=5Fmessages?= =?UTF-8?q?=E5=88=86=E6=B4=BE=E6=96=87=E6=A1=A3=EF=BC=9A=E4=B8=89=E4=B8=AA?= =?UTF-8?q?=E8=87=AA=E6=84=88tick=E6=9C=BA=E5=88=B6=E3=80=81=E5=90=84?= =?UTF-8?q?=E6=B6=88=E6=81=AF=E7=B1=BB=E5=9E=8B=E5=A4=84=E7=90=86=E8=AF=B4?= =?UTF-8?q?=E6=98=8E=E4=B8=8E=E7=BB=93=E6=9E=9C=E5=9B=9E=E4=BC=A0=E8=B7=AF?= =?UTF-8?q?=E5=BE=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Drivers/BSP/NET/net_socket.c | 90 ++++++++++++++++++++++++++++++++++-- 1 file changed, 85 insertions(+), 5 deletions(-) diff --git a/Drivers/BSP/NET/net_socket.c b/Drivers/BSP/NET/net_socket.c index d43b8018..58931110 100644 --- a/Drivers/BSP/NET/net_socket.c +++ b/Drivers/BSP/NET/net_socket.c @@ -496,10 +496,26 @@ static void net_reconcile_tick(void) { } /* - * 函数功能:处理消息队列中的请求 - * 限定条件:必须在 netTask 上下文中调用(独占 CH395F 和 s_net_socks 访问权) - * 函数说明:每次调用处理一条消息。处理 send/recv 时内部会调用 net_poll() - * 等待操作完成。处理完毕后通知调用方任务。 + * 函数功能:netTask 主循环核心 —— 自愈 tick 宿主 + 消息队列分派器。每轮 + * 先跑三个非阻塞自愈 tick(D10 重监听 / L3 挂起 recv / Trap 22 + * 状态对账),再非阻塞排空队列按 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) { net_msg_t msg; @@ -515,11 +531,25 @@ void net_process_messages(void) { net_pending_tick(); net_reconcile_tick(); /* Trap 22:芯片/本层状态周期对账(丢中断自愈) */ + /* 队列排空:超时 0 非阻塞取,直到本轮队列为空。do_notify=1 表示 + * 本条消息需要即时回执;=0 只出现在 RECV 挂起登记(返回哨兵 + * NET_PENDING_REGISTERED)——回执推迟到 net_pending_tick 完成检查 + * 发出,避免把"登记成功"误当成处理结果通知调用方。 */ while (osMessageQueueGet(netMsgQueueHandle, &msg, NULL, 0) == osOK) { int do_notify = 1; switch (msg.type) { 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); if (p_sock == NULL) { s_net_errno = NET_ERR_BADF; @@ -533,6 +563,21 @@ void net_process_messages(void) { break; } 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); if (p_sock == NULL) { s_net_errno = NET_ERR_BADF; @@ -549,6 +594,14 @@ void net_process_messages(void) { break; } 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); if (p_sock == NULL) { s_net_errno = NET_ERR_BADF; @@ -559,16 +612,39 @@ void net_process_messages(void) { break; } 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, (const struct net_sockaddr *)&msg.addr, msg.addrlen); break; } 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); break; } 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; int addrlen = msg.len; int *p_addrlen = (p_addr != NULL && addrlen > 0) ? &addrlen : NULL; @@ -609,7 +685,11 @@ void net_process_messages(void) { break; } default: - s_net_errno = NET_ERR; /* 未知消息类型:置通用错误码,保证回传值有效 */ + /* 未知消息类型(枚举闭合,正常不应触发):置通用错误码 + * NET_ERR、结果 -1,保证通知值永远有效——调用方通过 + * net_wait_result 拿到的是本条消息的确定结果,而非 + * 上一条消息的残留值。 */ + s_net_errno = NET_ERR; msg.result = -1; break; }