基于LWIP协议栈RAW API的 UDP传输实验

2023-05-16

什么是UDP?

UDP是用户数据报协议,是OSI参考模型中的传输层协议。

UDP的特点

缺点:无连接的,不可靠的,不能保证数据安全到达目的地。
优点:消耗资源小,处理速度快。

UDP通信的流程

  1. 创建一个udp协议控制块。
    使用函数:udp_new();
    返回udp_pcb *类型的指针。
  2. 建立“连接”。注意这里没有真正意义上的连接,没有握手挥手的过程。 只是设置了远端的ip地址和端口,也就是把远端的ip和端口保存到了udp协议控制块中。
    使用函数udp_connect建立“连接”。
    在UDP传输中建立“连接”并不是必须的。建立“连接”只是让远端的ip地址和端口保存到udp协议控制块中。
    如果执行了建立“连接”这个过程,那么后续可以使用udp_send函数去发送数据;
    如果没有执行建立“连接”这个过程,后续就必须使用udp_sendto函数去发送数据;
  3. 绑定,这个绑定是必须的,把本机的IP地址端口号,存储到udp协议控制块中。
    使用函数udp_bind
  4. 注册回调函数。这个函数会在UDP收到数据以后被调用。
  5. 经过上边的4步,可谓是万事俱备,只欠东风。我们可以发送数据了。
    这一步的核心是通过udp_send发送数据,不过还需要别的函数来打个辅助。
    1. 申请一段内存。使用pbuf_alloc函数。
    2. 拷贝数据到pbuf,使用函数pbuf_take
    3. 发送数据。使用函数udp_send
    4. 释放内存。使用函数pbuf_free
      这些辅助函数其实就是把要发送的数据组织成链表的形式,然后通过udp_send函数把链表的内容发送出去。

实验功能

开发板可以向PC机上的网络调试助手发送数据。
PC机上的网络调试助手向开发板发送数据。

部分实验源码:

udppcb=udp_new();//创建一个UDP
if(udppcb != NULL)
{
	//把远端ip地址整合到struct ip_addr类型的rmtipaddr变量中
	IP4_ADDR(&rmtipaddr, lwipdev.remoteip[0],lwipdev.remoteip[1],lwipdev.remoteip[2],lwipdev.remoteip[3]);
	err = udp_connect(udppcb, &rmtipaddr, UDP_DEMO_PORT);//建立"连接",这里只是把udppcb和rmtipaddr关联起来
	if(err == ERR_OK)
	{
		IP4_ADDR(&localaddr, lwipdev.ip[0],lwipdev.ip[1],lwipdev.ip[2],lwipdev.ip[3]);
		err = udp_bind(udppcb, &localaddr, UDP_DEMO_PORT);//绑定 把udppcb和本机ip关联起来
		if(err == ERR_OK)
		{
			udp_recv(udppcb, udp_demo_recv, NULL);//注册接收回调函数
			
			while(1)
			{
				ptr=pbuf_alloc(PBUF_TRANSPORT,strlen((char*)tcp_demo_sendbuf),PBUF_POOL); //申请内存
				if(ptr)
				{
					pbuf_take(ptr,(char*)tcp_demo_sendbuf,strlen((char*)tcp_demo_sendbuf)); //将tcp_demo_sendbuf中的数据拷贝到ptr所指地址处
					udp_send(udppcb,ptr);	//udp发送数据 
					pbuf_free(ptr);//释放内存
				} 
				delay_ms(100);//延时100ms
				lwip_periodic_handle();//lwip周期性处理的事务都在此函数	
				
				if(udp_demo_flag&1<<6)
				{
					printf("%s",udp_demo_recvbuf);
					udp_demo_flag&=~(1<<6);//标记数据已经被处理了.
				} 					
			}
		}
	}
}

在这里插入图片描述

开发板接收网络调试助手的数据

我们使用udp_recv函数注册好回调函数,回调函数会被lwip自动调用。
回调函数如下:

void udp_demo_recv(void *arg,struct udp_pcb *upcb,struct pbuf *p,struct ip_addr *addr,u16_t port)
{
	u32 data_len = 0;
	struct pbuf *q;
	if(p!=NULL)	//接收到不为空的数据时
	{
		memset(udp_demo_recvbuf,0,UDP_DEMO_RX_BUFSIZE);  //数据接收缓冲区清零
		for(q=p;q!=NULL;q=q->next)  //p指向的是pbuf类型的链表,
		{
			if(q->len > (UDP_DEMO_RX_BUFSIZE-data_len)) //本次要拷贝的数据长度大于剩余缓存长度 
				memcpy(udp_demo_recvbuf+data_len,q->payload,(UDP_DEMO_RX_BUFSIZE-data_len));//只能拷贝剩余缓存长度的数据,其余的丢掉
			else 
				memcpy(udp_demo_recvbuf+data_len,q->payload,q->len);//拷贝当前节点内的全部数据
			data_len += q->len;  	
			if(data_len > UDP_DEMO_RX_BUFSIZE) break; //超出TCP客户端接收数组,跳出	
		}
		udp_demo_flag|=1<<6;	//标记接收到数据了
		pbuf_free(p);//释放掉pbuf的内存
	}
}

我们先来看一下接收回调函数的类型定义。

/** Function prototype for udp pcb receive callback functions
 * addr and port are in same byte order as in the pcb
 * The callback is responsible for freeing the pbuf
 * if it's not used any more.
 *
 * ATTENTION: Be aware that 'addr' points into the pbuf 'p' so freeing this pbuf
 *            makes 'addr' invalid, too.
 *
 * @param arg user supplied argument (udp_pcb.recv_arg)
 * @param pcb the udp_pcb which received data
 * @param p the packet buffer that was received
 * @param addr the remote IP address from which the packet was received
 * @param port the remote port from which the packet was received
 */
typedef void (*udp_recv_fn)(void *arg, struct udp_pcb *pcb, struct pbuf *p,
    ip_addr_t *addr, u16_t port);

第一个参数arg:回调函数的参数。
第二个参数pcb:哪一个pcb接收到了数据
第三个参数p:接收数据的缓存区,是链表形式的
第四个参数addr:远端的ip
第五个参数port:远端的端口

pbuf节点串成一条链表, pbuf结构体成员变量payload指向了网络数据的缓存地址。我们只要处理pbuf链表就可以了,也就是把pbuf成员变量payload指向的缓存数据拷贝出来。
在接收回调函数中有两个重点工作,第一个就是拷贝数据,第二个就是释放内存。
下面是网络调试助手向开发板发送数据效果
在这里插入图片描述

不调用udp_connect函数发送数据

前面说过udp传输可以不调用udp_connect函数,发送的时候调用udp_sendto函数,验证一下是否可行。

udppcb=udp_new();//创建一个UDP
if(udppcb != NULL)
{
	//把远端ip地址整合到struct ip_addr类型的rmtipaddr变量中
	IP4_ADDR(&rmtipaddr, lwipdev.remoteip[0],lwipdev.remoteip[1],lwipdev.remoteip[2],lwipdev.remoteip[3]);
//	err = udp_connect(udppcb, &rmtipaddr, UDP_DEMO_PORT);//建立"连接",这里只是把udppcb和rmtipaddr关联起来
//	if(err == ERR_OK)
	{
		IP4_ADDR(&localaddr, lwipdev.ip[0],lwipdev.ip[1],lwipdev.ip[2],lwipdev.ip[3]);
		err = udp_bind(udppcb, &localaddr, UDP_DEMO_PORT);//绑定 把udppcb和本机ip关联起来
		if(err == ERR_OK)
		{
			udp_recv(udppcb, udp_demo_recv, NULL);//注册接收回调函数
			
			while(1)
			{
				ptr=pbuf_alloc(PBUF_TRANSPORT,strlen((char*)tcp_demo_sendbuf),PBUF_POOL); //申请内存
				if(ptr)
				{
					pbuf_take(ptr,(char*)tcp_demo_sendbuf,strlen((char*)tcp_demo_sendbuf)); //将tcp_demo_sendbuf中的数据拷贝到ptr所指地址处
					udp_sendto(udppcb, ptr,&rmtipaddr, UDP_DEMO_PORT);
//					udp_send(udppcb,ptr);	//udp发送数据 
					pbuf_free(ptr);//释放内存
				} 
				delay_ms(100);//延时100ms
				lwip_periodic_handle();//lwip周期性处理的事务都在此函数	
				
				if(udp_demo_flag&1<<6)
				{
					printf("%s",udp_demo_recvbuf);
					udp_demo_flag&=~(1<<6);//标记数据已经被处理了.
				} 					
			}
		}
	}
}

到此测试完成。
一个疑问:
打开网络调式助手,开发板发送的数据网络调试助手是收不到的,必须先用网络助手给开发板发送一包数据,然后网络调试助手才能收到开发板的数据。不知道为什么。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

基于LWIP协议栈RAW API的 UDP传输实验 的相关文章

  • PX4旋翼位置控制

    PX4旋翼位置控制 1 概括2 符号和函数说明2 1 符号说明2 2 函数说明 3 代码解析3 1 外环位置控制 positionController 3 2 内环速度控制 velocityController const float am
  • 数值分析(1)误差及误差分析

    数值分析1 误差及误差分析 第一章有效数有效数字和相对误差误差的数值运算条件数 第一章 有效数 定义 xff1a 某个数字 x x x 可以写成下面的形式
  • PX4 模块代码启动流程

    PX4模块代码启动流程 由于经常纠结程序代码启动流程 xff0c 以EKF2为例总结一下 版本 V1 9 0 源码路径 xff1a src modules ekf2 ekf2 main cpp 第一步 xff1a 启动时会进入和文件名相同的
  • PX4中的卡尔曼滤波——代码公式对照解释

    PX4中位置速度卡尔曼滤波解释 1 变量解释2 代码和公式对应2 1卡尔曼滤波公式 2 2 对应代码2 2 状态更新公式说明 3 总结 这篇博客以PX4中速度和位置估计来分析卡尔曼滤波过程 xff0c 将枯燥的公式和鲜活的代码联系起来 版本
  • PX4多传感器优先级判断

    PX4多传感器优先级判断 1 简介2 代码分析2 1 主体思路2 2 代码探究 这篇博客讨论了PX4在很多传感器下如何自动选择最优传感器 版本 xff1a v1 9 0 源码位置 xff1a src lib ecl sensors sens
  • PX4垂直起降过程研究总结

    这篇博客只要对垂直起降过程和控制逻辑进行分析 版本 xff1a V1 10 2 源码位置 xff1a src modules vtol att control vtol att control main cpp src modules vt
  • PX4 四元数旋翼姿态控制修正

    PX4 四元数旋翼姿态控制修正 1 四元数介绍2 旋翼四元数角度控制逻辑3 最终控制实现逻辑4 仿真验证 版本 xff1a V1 10 2 xff1b 源码位置 xff1a src modules ma att control ma att
  • PX4实践中遇到的问题总结(持续更新中!!!!)

    PX4实践中遇到的问题总结 xff08 持续更新中 xff01 xff01 xff09 1 解锁的时候各种传感器报错2 舵机莫名抖动3 起落架没法转向4 遥控器无法校准5 遥控器校准好之后操纵出现问题 1 解锁的时候各种传感器报错 如果是处
  • PX4 添加自定义参数

    PX4 添加自定义参数 PX4添加参数1 以添加参数 VT TILT MC 2 为例2 验证 PX4添加参数 1 以添加参数 VT TILT MC 2 为例 tiltrotor cpp 在构造函数里面初始化参数映射 params handl
  • Ubuntu系统中文乱码的解决办法

    Ubuntu系统中文乱码的解决办法 文章目录 Ubuntu系统中文乱码的解决办法1 安装中文语言2 安装语言设置的命令locale3 安装中文的相关字体4 修改语言的环境变量4 1 环境变量一4 2 设置二 5 正式配置语言后记 最近在do
  • Laf Assistant:云开发从未如此爽快!

    原文链接 xff1a https forum laf run d 67 工欲善其事 xff0c 必先利其器 在编写代码时 xff0c IDE 也是我们不可或缺的 它可以让我们更高效地完成代码编写 xff0c 提高开发效率 因此 xff0c
  • PX4垂起(Tiltrotor)偏航控制研究

    PX4垂起 xff08 Tiltrotor xff09 偏航控制研究 PX4垂起 xff08 Tiltrotor xff09 偏航控制研究1 问题描述2 过渡过程中为什么没有偏航角度控制问题1 xff1a 为什么在过渡阶段固定翼位置控制没有
  • PX4卡尔曼滤波分析

    PX4卡尔曼滤波分析 本文主要介绍了PX4中EKF相关的代码
  • 飞行器参数辨识-极大似然估计

    飞行器参数辨识 极大似然估计 1 理论1 1 极大似然估计一般理论1 2 极大似然估计应用在飞行器参数估计1 3 拟线性化求解带估计参数 2 程序实现2 1 飞行器运动的状态方程 1 理论 1 1 极大似然估计一般理论 n n n 个随机观
  • 使用opencv进行车牌提取及识别

    https blog csdn net u011808673 article details 78510692
  • ​天天干着打杂的活,你做好突破自我的觉悟了吗?

    天天干着打杂的活 xff0c 你做好突破自我的觉悟了吗 xff1f 本文为草核儿创作 xff0c 经授权在本公众号原创首发 关于作者 xff1a 草核儿 xff0c 互联网行业沉思者 xff01 希望传播的是正能量 xff0c 但偶尔会被误
  • 数据仓库系列:如何优雅地规划数仓体系

    0x00 前言 数仓规划是数仓建设的蓝图 xff0c 涵盖从需求分析开始到最终的数仓评估验收整个环境 xff1b 数仓规划之所以重要 xff0c 是因为它是描述了数据流动的概念性框架 xff0c 为元数据管理奠定了基础 xff0c 对数据加
  • 【实践案例分享】有赞数据仓库实践之路

    作者 xff1a 叶瑞典 团队 xff1a 数据中台 一 大数据环境下的有赞数仓 关于数据仓库 xff0c 在维基百科中将它定义为用于报表和数据分析的系统 xff0c 是商务智能 Business Intelligence 的核心部分 在数
  • 3分钟看懂用户标签体系怎么做

    随着越来越多的企业开始追求对用户的精细化运营 用各种手段延长用户的生命周期 xff0c 促进用户的活跃与转化 xff0c 并尽一切可能产生商业价值 xff0c 已经是运营的核心 而要做好精准化运营的第一步 xff0c 便是更好的认识我们的用
  • 数据运营系列(三):熵权法如何确定指标权重构建评价体系

    1 熵权法 信息论基本原理解释信息是系统有序性的度量单位 xff0c 而熵可以度量系统的无序程度 xff1b 如果某个指标的信息熵越小 xff0c 该指标提供的信息量越大 xff0c 指标变异程度 方差 高 xff0c 因此在综合评价中所起

随机推荐

  • 漫谈数据团队协作之各岗位间的相互尊重

    最近和几位资深的团队管理者聊团队协作 xff0c 受益匪浅 xff0c 其中有一个观点令居士印象深刻 xff1a 想让团队成员之间能够默契地协作 xff0c 有非常多的方法 xff0c 但是 xff0c 有一个很重要且很基本的要求是 xff
  • 【Proteus仿真】【STM32单片机】智能窗帘控制系统设计

    文章目录 一 功能简介二 软件设计三 实验现象联系作者 一 功能简介 本项目使用Proteus8仿真STM32单片机控制器 xff0c 使用LCD1602显示模块 按键模块 HC05蓝牙 DHT11温湿度 PCF8591 ADC模块 光线传
  • 直播PPT分享-如何体现数据同学的业务敏感度

    今天即兴给大家直播分享了一次 xff0c 反馈还比较不错 xff0c 不少童鞋私信我要ppt xff0c 这里就统一发出来给大家参考了 xff0c 其实内容很少 xff0c 6句话搞定 以后 xff0c 居士会不定期地直播分享 xff0c
  • 无题

    今天在思考一个问题 xff0c 关于互联网行业的 xff0c 其他行业还不太清楚不敢妄加评论 互联网行业在当前社会中其实面临着很多社会问题需要解决和探索 xff0c 比如职业发展的不确定性 35岁的职业危机 职业社交关系的难处理 xff0c
  • Markdown学习笔记:如何画流程图

    如何使用markdown画流程图 话说网上关于使用markdown画流程图的相关的教程真是一堆堆的坑 xff0c 我丝毫不怀疑这些博文作者确实是知道如何使用markdown画流程图了 xff0c 但是写出来的文章却丝毫没有明白具体的使用方法
  • Gradle打jar包,包含所有依赖

    前言 最近被gradle折腾的欲仙欲死 gradle想把所有依赖打进jar包主要有两种方式 xff1a 一种是重写jar动作 xff0c 一种是用第三方插件 为了装x xff0c 我一直都是用的第一种方式 xff0c 结果出了问题解决不了
  • Spring Data Rest如何暴露ID字段

    前言 为了懒省事 xff0c 使用Spring Data Rest来直接提供rest接口 xff0c 重点遇到点小坑 xff0c 记录一下 记录 问题 entity xff1a span class hljs annotation 64 E
  • hadoop清空回收站

    直接删除目录 xff08 不放入回收站 xff09 hdfs dfs span class hljs attribute rm span span class hljs attribute skipTrash span path span
  • 漫谈数据仓库之拉链表(原理、设计以及在Hive中的实现)

    0x00 前言 本文将会谈一谈在数据仓库中拉链表相关的内容 xff0c 包括它的原理 设计 以及在我们大数据场景下的实现方式 最新文章已经迁入公众 xff1a 木东居士 全文由下面几个部分组成 xff1a 先分享一下拉链表的用途 什么是拉链
  • 《数据仓库实践》

    序言 2017 年初 xff0c 我开始在简书上写关于数据仓库的系列博客 xff0c 博客主题围绕大数据场景下数据仓库的理论和实践来展开 xff0c 截止现在已有十篇左右 最初写作的时候主要是抱着学习和总结的态度 xff0c 导致很多地方略
  • 一种计算用户留存的方法

    0x00 概述 用户留存分析是互联网时代常用的一种数据分析方法 而很多快速发展的公司并没有相应的方法论沉淀 xff0c 这就导致了在计算用户留存的时候会出现下面的一些问题 xff1a 1 xff09 用户留存的定义不明确 xff0c 不同的
  • MAVLink--结构

    MAVLink源文件结构 MAVLink是为微型飞行器MAV xff08 Micro Air Vehicle xff09 设计的 xff08 LGPL xff09 开源的通讯协议 是无人飞行器和地面站 xff08 Ground Contro
  • 关于函数strtok和strtok_r的使用要点和实现原理(二)

    xff08 一 xff09 中已经介绍了使用strtok函数的一些注意事项 xff0c 本篇将介绍strtok的一个应用并引出strtok r函数 1 一个应用实例 网络上一个比较经典的例子是将字符串切分 xff0c 存入结构体中 如 xf
  • TX2 ubuntu CPU占用率、占用物理内存、占用虚拟内存、进程ID、系统温度

    文件解释 在实际工作中有时需要程序打印出某个进程的内存占用情况以作参考 下面介绍一种通过Linux下的伪文件系统 proc计算某进程内存占用的程序实现方法 首先 为什么会有所谓的 伪文件 呢 Linux系统的文件类型大致可分为三类 普通文件
  • 【Fast RTPS】入门--------Ubuntu系统下

    RTPS协议的简单介绍 在RTPS的顶层 xff0c Domain域定义了不同的通信层 几个域可以同时独立地共存 域包含任意数量的参与者Participants xff0c 即发送和接收数据的元素 参与者使用端Endpoints xff1a
  • Linux 内核配置选项(转)

    Linux 内核配置选项 from http www mitbbs com mitbbs article t php board 61 Linux amp gid 61 10715608 amp ftype 61 0 第一部分 01 Cod
  • Cortex-M3双堆栈MSP和PSP

    什么是栈 xff1f 在谈M3堆栈之前我们先回忆一下数据结构中的栈 栈是一种先进后出的数据结构 类似于枪支的弹夹 xff0c 先放入的子弹最后打出 xff0c 后放入的子弹先打出 M3内核的堆栈也不例外 xff0c 也是先进后出的 栈的作用
  • 烧毁DC/DC电路问题

    使用芯龙半导体的XL7005A DC DC芯片 已经很多年了 xff0c 用的也很稳定 这次在做一个设备的时候 xff0c 系统上电就会烧DC DC芯片以及系统电路中的LDO和MCU等 试了很多次终于发现规律了 xff0c DC DC电路就
  • FreeRTOS内核全局变量

    想要分析FreeRTOS源码 xff0c 想要理解FreeRTOS源码的整个宏观架构 xff0c 有一个前提就是必须知道FreeRTOS内核中那些全局变量的意义 xff0c 每个全局变量都是用来干什么的 只有了解了这些全局变量我们才能从宏观
  • 基于LWIP协议栈RAW API的 UDP传输实验

    什么是UDP xff1f UDP是用户数据报协议 xff0c 是OSI参考模型中的传输层协议 UDP的特点 缺点 xff1a 无连接的 xff0c 不可靠的 xff0c 不能保证数据安全到达目的地 优点 xff1a 消耗资源小 xff0c