fix(net/udp): 收包剥头只看芯片宣布的字节数,与 udp_mode 无关(#73)
真机第一轮(2026-11-04 08:16,阶段 16 台架)把本轮最大的一条设计错误照了出来: TC-NET-1603 在客户端形态下发 48 字节应答,板子读到的是 `n=56`、首字节 `0x38` ——56 正是信息头的长度字段,也就是**头还在**,而我把它的 8 字节当成了载荷。 设计时按手册 §9.2.4 读出一句"客户端模式不带信息头",就以为运行时把 DesIP 从 全 F 改成具体对端会让头消失。真机给的定案是:**加不加 8 字节信息头,是在 OPEN_SOCKET 那一刻由当时的 DesIP 定死的**,之后再改 DesIP 只改发送去向与芯片 的收包源过滤,不改收包帧格式。本层 `net_bind` 一律以 DesIP=0xFFFFFFFF 开 Socket,所以对本层的 UDP socket 而言头恒在、恒剥。 - `net_udp_datagram_read` 的剥头条件由 `udp_mode == SERVER && avail >= 8` 改为 **只看 `avail >= 8`**;源地址一律从信息头里取——头里的源 IP/端口是本包的真实 来源,比"我把包发给了谁"这本账更准(NAT 后的时间服务器就是两种地址不一致的 那种)。 - 不足 8 字节的残包保持既有定案(TC-NETSOCK-440o):无从判头,整包按载荷交付, 源地址退到对端记账。这也是 `net_udp_src_from_peer()` 如今唯一的读者。 - `udp_mode` 语义收窄为"芯片的对端过滤 + 发送去向",**不描述收包帧格式**; `net_types.h` 的 UDP 形态块、两个模式宏的注释、`net_sendto` / `net_recvfrom` 的函数说明一并按定案改写。字段本身没动,仍复用原有的 2 字节 padding,RAM 零增长。 产品构型 Keil 构建 0 Error 0 Warning,`Code=249120 RO=29836 RW=2052 ZI=149996`, 与改造前的产品基线同尺寸。判据文字与真机证据见同批的测试、文档提交。
This commit is contained in:
@@ -2629,14 +2629,17 @@ int net_drop_conn(int sockfd) {
|
||||
* 取代 2026-10-24「先把危险面关掉」的临时守卫 NET_ERR_NOT_IN_NETTASK)。
|
||||
* 执行任务(netTask,或硬件层的 testTask)上下文直接执行不投自己——
|
||||
* 板级用例仍可在自己任务里裸调本接口。
|
||||
* 3. 带 dest_addr 会把芯片切成 **UDP 客户端模式**(DesIP=具体 IP):此后芯片
|
||||
* 只收该 IP 的包、且不再附带 8 字节信息头。本层按 p_sock->udp_mode 记账,
|
||||
* net_recvfrom 据此决定剥不剥头——改造前恒剥头,客户端模式下会吃掉
|
||||
* 载荷前 8 字节并回填一个假源地址(SNTP 这类"请求-应答"用法必踩)。
|
||||
* 3. 带 dest_addr 会把芯片的对端约束切成 **UDP 客户端形态**(DesIP=具体 IP):
|
||||
* 此后芯片只收该 IP 的包、发送也固定走它。⚠ 8 字节信息头并不因此消失:
|
||||
* 头在不在取决于**开 Socket 那一刻**的 DesIP(本层一律 0xFFFFFFFF),
|
||||
* 2026-11-04 08:16 真机 TC-NET-1603 实测 48 B 载荷可读 56 B、首字节 0x38。
|
||||
* 本层按 p_sock->udp_mode 只记这份对端账,net_recvfrom 一律剥头、一律从
|
||||
* 头里取源地址(为什么不能按 udp_mode 决定剥不剥,见 net_types.h UDP 形态
|
||||
* 注释与 TRAP-NET-22 的 2026-11-04 追加段)。
|
||||
* 4. 分块粒度、停滞超时、挂起 send 续传与 TCP 共用 net_send_locked,
|
||||
* 不留第二份自旋。单包超过 NET_SEND_CHUNK_MAX(1024) 会被写成多个数据报
|
||||
* (改造前后一致);一个应用数据报请控制在 1024 B 内。
|
||||
* 5. dest_addr == NULL = 不改 DesIP,沿用上次的对端(与改造前一致)。
|
||||
* 5. dest_addr == NULL = 不改 DesIP,沿用上一次写进芯片的对端(与改造前一致)。
|
||||
* 6. flags 目前不被本层使用(与改造前一致,发送不接受 DONTWAIT 语义)。
|
||||
* 7. 直接路径(执行任务上下文)不做挂起续传:芯片发送缓冲超 2 ms 未腾出时
|
||||
* 返回 NET_ERR_BUSY,而不是像改造前那样自旋到 1000 ms 后短写。
|
||||
@@ -2733,11 +2736,14 @@ int net_sendto(int sockfd, const void *buf, int len, int flags,
|
||||
* 返回值:实际接收字节数 int > 0 || -1
|
||||
* -1 - 接收失败(精确码见本任务 net_get_errno()) int
|
||||
* 限定条件:Socket 已创建且为 UDP 类型(SOCK_DGRAM)**并已 net_bind**;net_init() 已调用
|
||||
* 函数说明:1. 一次调用交付**一个完整数据报**:服务器模式剥掉芯片的 8 字节信息头并
|
||||
* 据此填 src_addr;客户端模式整包都是载荷、src_addr 取本 Socket 的固定
|
||||
* 对端(芯片在该模式下不加头,见 net_types.h UDP 模式宏注释)。
|
||||
* 剥不剥头按 p_sock->udp_mode 判定,不再按"字节数 >= 8"猜——猜错即吃掉
|
||||
* 载荷前 8 字节(本接口改造前的缺陷,SNTP 应答 48 B 会只剩 40 B)。
|
||||
* 函数说明:1. 一次调用交付**一个完整数据报**:剥掉芯片的 8 字节信息头并据此填
|
||||
* src_addr。剥头**不看 udp_mode**——本层 Socket 一律在 DesIP=0xFFFFFFFF
|
||||
* 的形态下开出,芯片就给每个收到的数据报加头,运行时把 DesIP 改成具体
|
||||
* 对端(显式 dest_addr 的 net_sendto / net_udp_set_peer)并不会让头消失
|
||||
* (2026-11-04 08:16 真机 TC-NET-1603 实测:客户端形态下 48 B 载荷可读
|
||||
* 56 B、首字节 0x38 = 信息头长度字段;详见 net_types.h UDP 形态注释与
|
||||
* TRAP-NET-22 的 2026-11-04 追加段)。只有不足 8 字节的残包无从判头,
|
||||
* 整包按载荷交付、源地址退到本 Socket 的对端记账。
|
||||
* 2. 载荷超出 len 时交付前 len 字节并把剩余部分**读空丢弃**(手册 §9.2.4
|
||||
* 要求服务器模式一次性读完;留半包会让下一个数据报从尾巴开始解析)。
|
||||
* 3. 无数据时(与 net_recv 同构):DONTWAIT / 非阻塞属性立即返回 -1
|
||||
@@ -2858,8 +2864,10 @@ int net_udp_set_peer(int sockfd, const struct net_sockaddr_in *peer) {
|
||||
* 出口参数:无
|
||||
* 返回值:NET_UDP_MODE_SERVER / NET_UDP_MODE_CLIENT;-1 = 描述符非法 int
|
||||
* 限定条件:无(纯读控制块,任意上下文)
|
||||
* 函数说明:给调用方与自测用:sendto(带目的地址) 之后模式是 CLIENT,此时
|
||||
* recvfrom 不剥信息头;bind 之后是 SERVER。
|
||||
* 函数说明:给调用方与自测用:它报的是**对端形态**(下一次不带地址的 sendto 发往
|
||||
* 谁)——sendto(带目的地址) 之后是 CLIENT,bind / set_peer(NULL) 之后是
|
||||
* SERVER。收包帧格式与之无关:本层 Socket 恒在全 F 形态下 open,芯片恒
|
||||
* 前置 8 字节信息头,recvfrom 两种形态都剥(TRAP-NET-22 追加段)。
|
||||
*/
|
||||
int net_udp_get_mode(int sockfd) {
|
||||
const net_sock_t *p_sock = net_get_sock(sockfd);
|
||||
|
||||
Reference in New Issue
Block a user