From 4ce966dfb84fdd504f9d367f22dd45d8b8c5acec Mon Sep 17 00:00:00 2001 From: Wanderingss <1624155937@qq.com> Date: Tue, 22 Sep 2026 15:37:19 +0800 Subject: [PATCH] =?UTF-8?q?net=5Frecv=5Fto=E8=A1=A5=E5=85=A8=E5=88=86?= =?UTF-8?q?=E6=AD=A5=E6=B3=A8=E9=87=8A=EF=BC=9A=E7=89=87=E8=B6=85=E6=97=B6?= =?UTF-8?q?-2=E8=BF=94=E5=9B=9E=E7=A0=81=E4=B8=8D=E4=BE=9D=E8=B5=96errno?= =?UTF-8?q?=E4=BE=9D=E6=8D=AE=E3=80=81=E5=80=BC=E6=8B=B7=E8=B4=9D=E9=98=9F?= =?UTF-8?q?=E5=88=97=E9=99=B7=E9=98=B1=E3=80=81=E4=B8=89=E5=88=86=E6=94=AF?= =?UTF-8?q?=E8=BF=94=E5=9B=9E=E8=AF=AD=E4=B9=89=EF=BC=88E-02=E9=85=8D?= =?UTF-8?q?=E5=A5=97=E7=95=99=E6=A1=A3=EF=BC=8C=E6=97=A0=E9=80=BB=E8=BE=91?= =?UTF-8?q?=E5=8F=98=E5=8C=96=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Drivers/BSP/NET/net_socket.c | 54 ++++++++++++++++++++++++++---------- 1 file changed, 39 insertions(+), 15 deletions(-) diff --git a/Drivers/BSP/NET/net_socket.c b/Drivers/BSP/NET/net_socket.c index d8f3f4e5..91f75d8b 100644 --- a/Drivers/BSP/NET/net_socket.c +++ b/Drivers/BSP/NET/net_socket.c @@ -1490,46 +1490,70 @@ int net_recv(int sockfd, void *buf, int len, int flags) { * 超时用独立返回码 -2(而非靠 errno 区分)→ 无跨任务 errno 竞态。 */ int net_recv_to(int sockfd, void *buf, int len, uint32_t timeout_ms) { - net_msg_t msg; + net_msg_t msg; /* 一次性消息结构体:队列按值存结构副本(仅指针、不拷数据),入队后由 netTask 取出处理 */ + /* ---- 1. 参数合法性检查 ---- */ if (sockfd < 0 || sockfd >= NET_MAX_SOCKETS) { - s_net_errno = NET_ERR_BADF; + s_net_errno = NET_ERR_BADF; /* 描述符越界 */ return -1; } + /* ---- 2. 运行环境检查:消息队列须已创建(网络层已初始化) ---- */ if (netMsgQueueHandle == NULL) { - s_net_errno = NET_ERR; + s_net_errno = NET_ERR; /* 网络层未初始化 */ return -1; } + /* ---- 3. 分片长度检查:timeout_ms = 0 在 netTask 侧意味着"改用默认 + * NET_RECV_TIMEOUT_MS(30 秒)",恰是本接口要规避的长阻塞,直接拒绝 ---- */ if (timeout_ms == 0U) { - s_net_errno = NET_ERR_INVAL; + s_net_errno = NET_ERR_INVAL; /* 分片长度必须 > 0 */ return -1; } - msg.type = NET_MSG_RECV; - msg.sockfd = sockfd; - msg.buf = buf; - msg.len = len; - msg.flags = 0; /* 阻塞式(分片有界) */ - msg.timeout_ms = timeout_ms; /* 调用方指定(分片长度) */ - msg.caller = xTaskGetCurrentTaskHandle(); - msg.result = -1; + /* ---- 4. 组装消息:把本次分片读的全部上下文填入 msg ---- */ + msg.type = NET_MSG_RECV; /* 消息类型,netTask 据此分派到 net_recv_locked */ + msg.sockfd = sockfd; /* 目标 Socket */ + msg.buf = buf; /* 接收缓冲(队列仅拷贝指针,buf 须有效至本函数返回) */ + msg.len = len; /* 缓冲容量:单次读取字节数上限(允许部分读) */ + msg.flags = 0; /* 阻塞式:netTask 侧轮询至"有数据"或"本片超时"(勿置 NET_MSG_DONTWAIT) */ + msg.timeout_ms = timeout_ms; /* 本片预算:netTask 最多等待 timeout_ms,保证对 netTask 的占用有界(E-02) */ + msg.caller = xTaskGetCurrentTaskHandle(); /* 记录调用任务句柄,netTask 处理后经 xTaskNotify() 精准回执 */ + msg.result = -1; /* 预置失败(仅防御值;真实结果经任务通知值回传,见步骤 6) */ + /* ---- 5. 入队:将消息投递给 netTask,osWaitForever 表示队列满时阻塞调用方 ---- */ if (osMessageQueuePut(netMsgQueueHandle, &msg, 0, osWaitForever) != osOK) { - s_net_errno = NET_ERR_BUSY; + s_net_errno = NET_ERR_BUSY; /* 入队失败(队列异常等极端情况) */ return -1; } - msg.result = net_wait_result("rcv", sockfd); + /* ---- 6. 阻塞等待 netTask 处理完毕:netTask 执行 net_recv_locked 后经 + * xTaskNotify() 把结果(字节数 / 0 / 负错误码)以 32 位通知值回传本任务; + * 注意 net_msg_t 按值拷入队列,队列里的 result 字段不会回来—— + * 通知值是唯一的真实回传通道(勿给 net_msg_t 加"回传用"字段) ---- */ + msg.result = net_wait_result("rcv", sockfd); /* 两段式等待:零等待拾取 + 阻塞,防丢失通知(见 net_wait_result) */ + /* ---- 7. 回传结果(三分支:分片超时 / 真错误 / 数据或 EOF) ---- */ if (msg.result == NET_ERR_TIMEDOUT) { - return -2; /* 本片超时:非致命 */ + /* 本片超时:timeout_ms 内未等到数据,非致命。 + * 超时只凭返回码 -2 判定、不得依赖 errno:s_net_errno 是跨任务共享的 + * 全局量,netTask 处理本片时写入的 NET_ERR_TIMEDOUT 随时可能被其他任务 + * 的 net 调用覆盖;而返回码是 netTask 经任务通知值专为本任务回传的, + * 天然无竞态(本分支也不再改写 s_net_errno)。 + * 调用方见到 -2 后累计自身总超时预算,决定是否发起下一片。 + * (本判断必须先于下方通用 <0 分支:NET_ERR_TIMEDOUT = -9 同样满足 <0) */ + return -2; } if (msg.result < 0) { + /* 真错误:netTask 把具体错误码(如 NET_ERR_WOULDBLOCK)以负值回传, + * 此处恢复为线程级错误码(可经 net_get_errno() 读取); + * 对外保持 BSD 语义——失败一律返回 -1 */ s_net_errno = msg.result; return -1; } + + /* >= 0:0 = 对端关闭(EOF,net 层尽力自动重监听,失败由重试轮询接管); + * > 0 = 实际接收字节数(可能小于 len,属正常部分读) */ return msg.result; }