UDP报文的数据结构

主要内容参照https://doc.embedfire.com/net/lwip/zh/latest/doc/chapter14/chapter14.html#id6,整理出来自用。

1. UDP 报文首部结构体(udp_hdr)

        为清晰定义 UDP 报文首部的各个字段,LwIP 设计了udp_hdr结构体,其包含 4 个核心字段,具体结构通过代码定义,各字段功能如下:

  • srcdest:均为 16 位无符号整数(u16_t),分别表示 UDP 通信的源端口号和目的端口号,用于标识通信双方的应用进程。
  • len:16 位无符号整数,代表 UDP 报文的总长度(包括首部和数据部分)。
  • chksum:16 位无符号整数,用于 UDP 报文的校验和计算,保障数据传输的完整性(若值为 0 则表示不进行校验)。

        结构体定义中使用PACK_STRUCT相关宏,是为了确保结构体在内存中紧凑存储,避免因编译器对齐规则导致字段偏移,保证数据解析的准确性。

2. UDP 控制块(udp_pcb)

        与 TCP 类似,LwIP 通过 “UDP 控制块” 管理 UDP 通信的所有关键信息,每个基于 UDP 的应用线程都会对应一个控制块,并与特定端口绑定,以便系统识别和处理该应用的 UDP 数据。

(1)控制块的核心组成

UDP 控制块结构体(udp_pcb)的内容可分为两部分:

#define IP_PCB                             \/* 本地ip地址与远端IP地址 */             \ip_addr_t local_ip;                      \ip_addr_t remote_ip;                     \/* 网卡id */                             \u8_t netif_idx;                          \/* Socket 选项 */                        \u8_t so_options;                         \/* 服务类型   */                         \u8_t tos;                                \/* 生存时间 */                           \u8_t ttl                                 \IP_PCB_NETIFHINT/** UDP控制块 */struct udp_pcb{IP_PCB;//指向下一个控制块struct udp_pcb *next;//控制块状态u8_t flags;/** 本地端口号与远端端口号 */u16_t local_port, remote_port;/** 接收回调函数 */udp_recv_fn recv;/** 回调函数参数 */void *recv_arg;};
  • 复用 IP 层信息:通过引入IP_PCB宏,直接包含 IP 层通信所需的基础信息,如本地 IP 地址、远端(目标)IP 地址、网卡 ID(netif_idx)、Socket 选项(so_options)、服务类型(tos)和生存时间(ttl),避免信息重复定义,简化 IP 层与 UDP 层的交互。
  • UDP 层专属信息:包括控制块链表指针(next,用于连接多个控制块)、控制块状态标识(flags)、本地端口号与远端端口号(local_portremote_port,核心标识字段,用于匹配应用线程),以及接收数据的回调函数(recv)和回调参数(recv_arg,用于数据递交给上层应用)。
(2)控制块的管理方式

        LwIP 会将所有 UDP 控制块通过next指针串联成一个链表,链表的头节点由全局变量udp_pcbs记录。这种链表结构便于系统在处理 UDP 数据时,通过遍历链表快速查找对应的控制块,提高数据处理效率。

(3)回调函数的注册

        回调函数(udp_recv_fn)是 UDP 层向应用层递交数据的关键接口,其函数原型(见原文代码清单 14_3)规定了参数格式:回调参数(arg)、对应的 UDP 控制块(pcb)、存储数据的缓冲区(pbuf)、数据来源的 IP 地址(addr)和端口号(port)。

        回调函数的注册通过udp_recv函数实现:该函数将用户定义(或系统默认)的回调函数及其参数,分别赋值给控制块的recvrecv_arg字段。实际开发中,若使用 NETCONN API 或 Socket API,LwIP 内核会自动注册recv_udp作为回调函数,无需用户手动实现;若使用 RAW API,则需用户自行定义并注册回调函数。

二、UDP 报文发送流程

        UDP 作为传输层协议,需接收上层应用数据并添加首部后,交付给 IP 层发送,核心逻辑由udp_sendto_if_src函数实现,整体流程简洁,具体步骤如下:

  1. 端口绑定检查:若当前 UDP 控制块未绑定本地端口(local_port为 0),则先调用udp_bind函数完成端口绑定,确保数据能被正确识别和处理。
  2. 数据长度与内存检查
    • 校验数据总长度:判断添加 UDP 首部(长度为 UDP_HLEN)后,总长度是否超过 16 位整数的最大值(避免溢出),若超过则返回内存错误(ERR_MEM)。
    • 检查缓冲区空间:尝试在当前数据缓冲区(pbuf)头部预留 UDP 首部空间,若空间不足,则新分配一个仅存储首部的pbuf,并与原数据缓冲区链接成链表(pbuf_chain)。
  3. 填充 UDP 首部:将控制块中的本地端口号、目标端口号,以及缓冲区总长度(转换为网络字节序,通过lwip_htons函数),分别填入 UDP 首部的srcdestlen字段;校验和字段(chksum)默认设为 0(表示不校验,可根据需求调整)。
  4. 交付 IP 层发送:调用ip_output_if_src函数,将封装好 UDP 首部的数据交付给 IP 层,由 IP 层负责通过指定网卡(netif)发送到目标地址;发送完成后,根据缓冲区是否为新分配,决定是否释放内存(pbuf_free),并更新相关统计指标(如udp.xmitmib2.udpoutdatagrams)。

        相较于 TCP,UDP 发送流程无需建立连接、重传确认等复杂逻辑,仅需完成首部封装和层间交付,处理效率更高。

三、UDP 报文接收流程

        当 IP 层接收到 UDP 报文后,会调用udp_input函数将数据递交给 UDP 层处理,核心是通过匹配控制块找到对应应用,并完成数据递交,具体步骤如下:

  1. 合法性初步校验

    • 检查报文长度:若当前缓冲区长度小于 UDP 首部长度(UDP_HLEN),则判定为无效报文,更新错误统计(如udp.lenerr)并释放缓冲区,直接结束处理。
    • 解析基础信息:提取 UDP 首部(转换为udp_hdr类型),判断报文是否为广播包(ip_addr_isbroadcast),并将源端口号、目的端口号从网络字节序转换为主机字节序(lwip_ntohs)。
  2. 遍历控制块链表匹配应用

    • 遍历udp_pcbs链表,对比控制块的 “本地端口号” 与报文的 “目的端口号”,同时通过udp_input_local_match函数校验 IP 地址匹配性(本地 IP 与报文目的 IP),筛选出候选控制块。
    • 进一步筛选 “完全匹配” 的控制块:在候选控制块中,对比控制块的 “远端端口号” 与报文的 “源端口号”、控制块的 “远端 IP” 与报文的 “源 IP”,若均匹配,则确定为目标控制块;若存在多个候选,会将完全匹配的控制块移至链表头部,优化后续查找效率。
    • 无完全匹配时的处理:若未找到完全匹配的控制块,会选取第一个未绑定远端信息(UDP_FLAGS_CONNECTED未置位)的候选控制块作为替代;若仍无候选,则判定为 “无对应应用”。
  3. 数据递交或差错反馈

    • 数据递交(找到对应控制块):先从缓冲区中移除 UDP 首部(pbuf_remove_header),提取纯数据部分;若控制块已注册回调函数(recv不为空),则调用该函数,将数据、源 IP、源端口等信息递交给上层应用(回调函数需负责后续缓冲区释放);若未注册回调函数,则直接释放缓冲区。
    • 差错反馈(无对应控制块):若报文非广播包或多播包,会构造 “端口不可达” 的 ICMP 差错报文(通过icmp_port_unreach函数),反馈给报文源主机,同时释放缓冲区并更新统计指标(如udp.proterrmib2.udpnoports)。
  4. 资源清理与统计更新:处理结束后,释放相关资源(如缓冲区),停止性能计时(PERF_STOP),并更新 UDP 接收相关的统计数据(如udp.recvmib2.udpindatagrams)。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/web/94171.shtml
繁体地址,请注明出处:http://hk.pswp.cn/web/94171.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

图论与最短路学习笔记

图论与最短路在数学建模中的应用 一、图论模型图 G(V,E)G(V,E)G(V,E) VVV:顶点集合EEE:边集合每条边 (u,v)(u,v)(u,v) 赋予权值 w(u,v)w(u,v)w(u,v),可用 邻接矩阵 或 邻接表 表示。二、最短路问题的数学形式 目标:寻找从源点 sss…

第九节 Spring 基于构造函数的依赖注入

当容器调用带有一组参数的类构造函数时,基于构造函数的 DI 就完成了,其中每个参数代表一个对其他类的依赖。接下来,我们将通过示例来理解 Spring 基于构造函数的依赖注入。示例:下面的例子显示了一个类 TextEditor,只能…

【数据库】PostgreSQL详解:企业级关系型数据库

文章目录什么是PostgreSQL?核心特性1. 标准兼容性2. 扩展性3. 高级功能4. 可靠性数据类型1. 基本数据类型2. 高级数据类型基本操作1. 数据库操作2. 表操作3. 数据操作高级查询1. 连接查询2. 子查询3. 窗口函数JSON操作1. JSON数据类型2. JSON查询3. JSON索引全文搜索…

FFMPEG相关解密,打水印,合并,推流,

1:ffmepg进行打水印解密 前提ffmepg安装利用静态版就可以这个什么都有,不用再配置其他信息:(这个利用ffmpeg终端命令是没问题的,但是如果要是再C中调用ffmpeg库那么还需要从新编译安装下) 各个版本 Inde…

MySql知识梳理之DML语句

注意: 插入数据时,指定的字段顺序需要与值的顺序是一一对应的。 字符串和日期型数据应该包含在引号中。 插入的数据大小,应该在字段的规定范围内注意:修改语句的条件可以有,也可以没有,如果没有条件,则会修改整张表的所…

GaussDB GaussDB 数据库架构师修炼(十八)SQL引擎-SQL执行流程

1 SQL执行流程查询解析:词法分析、语法分析、 语义分析 查询重写:视图和规则展开、基于规则的查询优化 计划生成:路径搜索和枚举、选出最优执行计划 查询执行:基于优化器生成的物理执行计划对数据进行获取和计算2 解析器和优化器S…

grpc 1.45.2 在ubuntu中的编译

要在 Ubuntu 上编译 gRPC 1.45.2,需要按照以下步骤操作。以下指南基于 gRPC 官方文档和相关资源,确保环境配置正确并成功编译。请确保你有管理员权限(sudo)以安装依赖项和执行相关命令。 1. 准备环境 确保你的 Ubuntu 系统已安装…

lesson45:Linux基础入门指南:从内核到实践操作全解析

目录 一、Linux简介与核心概念 1.1 Linux的起源与发展 1.2 内核与发行版的关系 二、Linux内核版本解析 2.1 内核版本命名规则 2.2 2025年主流内核版本 三、主流Linux发行版对比 3.1 桌面用户首选 Ubuntu 24.04 LTS Linux Mint 22 3.2 技术爱好者之选 Fedora 41 Ar…

PCL点云库入门(第24讲)——PCL库点云特征之NARF特征描述 Normal Aligned Radial Feature(NARF)

一、算法原理 1、NARF 特征概述 NARF(Normal Aligned Radial Feature)是 2011 年由 Bastian Steder 等人在论文 《Point Feature Extraction on 3D Range Scans Taking into Account Object Boundaries》中提出的一种 稀疏局部 3D 特征描述子。 核心目标是提取具有“边界意…

使用 eventpp 构建跨 RT-Thread 与 ARM-Linux 的轻量级 Active Object(AO)事件驱动框架

0. 引言 本文展示一个实践路径:以轻量级 C 事件库 eventpp 为核心,设计并实现一个面向嵌入式的、可移植的 Active Object(AO)事件驱动架构。该架构满足以下目标: 跨平台兼容:单套代码在 RT-Thread&#xff…

【python实用小脚本-193】Python全能PDF小助手:剪切/合并/旋转/加密一条龙——再也不用开会员

Python全能PDF小助手:剪切/合并/旋转/加密一条龙——再也不用开会员 PDF编辑, 本地处理, 零会员费, 多功能脚本, 瑞士军刀 故事开场:一把瑞士军刀救了周五下班的你 周五 17:55,老板甩来一堆 PDF: “把第 3、7 页删掉”“再和合同合…

Ubuntu根分区扩容

目录 1.先查看/dev/sda 整块磁盘设备的分区占用情况: 2.在VMware中编辑虚拟机: 3.进入虚拟机,进入disk应用程序: 4.扩容文件系统 5.最后通过df-h lsblk或通过可视化GParted进行验证。 1.先查看/dev/sda 整块磁盘设备的分区占…

智慧城市SaaS平台/市政设施运行监测系统之空气质量监测系统、VOC气体监测系统、污水水质监测系统及环卫车辆定位调度系统架构内容

1. 空气质量监测系统1) 监测点管理 a) 监测点基本信息 支持记录空气质量监测点的名称、位置、类型、设备配置等信息。 b) 监测点分布地图 支持通过GIS地图展示监测点的分布情况,支持地图查询和导航。 2) 空气质量监测 a) 实时数据采集 支持实时采集空气质量数据&…

PiscCode迅速集成YOLO-Pose 实现姿态关键点轨迹跟踪应用

在计算机视觉领域,人体姿态检测与轨迹跟踪是很多应用场景的核心技术,例如运动分析、行为识别、智能监控等。本文将介绍如何在 PiscCode 平台上,利用 YOLO-Pose 模型进行姿态估计,并实现多人关键点轨迹跟踪。 一、什么是 PiscCode …

HTTP的状态码有哪些,并用例子说明一下

问题HTTP的状态码有哪些,并用例子说明一下我的回答HTTP状态码是服务器对客户端请求的响应码,它们按照不同的功能被分为五大类。我来介绍一下主要的状态码及其实际应用场景:1xx(信息性状态码):表示请求已接收…

【51单片机】【protues仿真】基于51单片机宠物投食器系统

目录 一、主要功能 二、使用步骤 三、硬件资源 四、软件设计 五、实验现象 一、主要功能 1、LCD1602液晶显示当前时间 2、按键设置时间,5个定时投喂时间​ 3、可以通过手动按键进行投喂食物 4、步进电机模拟投喂食物 二、使用步骤 基于51单片机的宠物自动投…

掌握设计模式--命令模式

命令模式(Command Pattern) 命令模式(Command Pattern)是一种行为型设计模式,它将请求(命令)封装成对象,从而使您能够参数化客户端(调用者)使用不同的请求、…

STM32之beep、多文件、延迟、按键以及呼吸灯

一、Beep控制 原理图分析: 蜂鸣器三极管控制引脚对应 MCU PB8。当前蜂鸣器对应的电路中,三极管是 NPN 三极管,当前【基极】存在小电流,当前三极管导通。要求对应 PB8 引脚对外输出电压 / 电流。当前 PB8 输出高电平,当…

C++的struct里面可以放函数,讨论一下C++和C关于struct的使用区别

我们来看一个C代码下面的struct结构体: struct UserValue {float lx;float ly;float rx;float ry;float L2;// 【构造函数】UserValue() {setZero();}// 【成员函数】void setZero() {lx 0;ly 0;rx 0;ry 0;L2 0;} };在这篇文章中,我们将来详细解释一下为什么 U…

【Kubernetes知识点】资源配额与访问控制

目录 1.解释ResourceQuota的作用。 2.解释Service Account的用途。 3.详细解释Role和ClusterRole。 4.什么是K8s的NetworkPolicy? 5.详细描述在K8s中如何控制跨Namespace的Pod访问? 1.解释ResourceQuota的作用。 ResourceQuota(资源配额…