在 uboot 中实现 UDP 协议

一、明确背景

        uboot中有许多通信协议,像TFTP、NFS等,这些协议底层都是基于UDP协议来实现的,由于有一个板子在 uboot 段进行固件下载更新的需求,本来想基于TCP协议来实现自定义通信协议(TCP有自带的拥塞控制和重传机制)。但是,uboot底层并不支持TCP协议栈,且TCP协议栈的默认超时重传时间过长,移植TCP协议栈到uboot中难度也是相当大。最后结合需求考虑下来,决定基于UDP协议来实现自定义通信协议。第一步,要先验证UDP协议能否走通(不用想大概率是可以的,因为uboot中支持的其他协议底层也是基于UDP的,但还是走一遍验证一下,也是为后面的自定义通信协议打好基础)

        抓住一个思想:TFTP底层就是基于UDP的,有什么不清楚的地方就看uboot中的TFTP源码,往往会指出些方向。

二、代码实现

        首先在common/cmd_net.c中添加如下代码,这一步的目的是在uboot的命令中添加一个名为udp的命令,当我们在控制台输入udp后便会执行do_udp函数,然后逐层往下调用其他函数

/*my UDP*/
int do_udp(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
{int ret;ret = netboot_common_udp(UDP, cmdtp, argc, argv);return ret;
}U_BOOT_CMD(udp,    6,      1,      do_udp,"send or recv message to from server using UDP protocol","[udp]"
);

接着继续在该文件中定义这样一个函数,该函数是用来处理uboot控制台输入的具体命令参数的

/*my netboot_common*/
static int netboot_common_udp(enum proto_t proto, cmd_tbl_t *cmdtp, int argc, char *argv[])
{int   rcode = 0;int   size;switch (argc){case 1:break;case 2:pkt_data = argv[1];break;default:bootstage_error(BOOTSTAGE_ID_NET_START);return CMD_RET_USAGE;}bootstage_mark(BOOTSTAGE_ID_NET_START);if ((size = NetLoop(proto)) < 0) {bootstage_error(BOOTSTAGE_ID_NET_NETLOOP_OK);return 1;}bootstage_mark(BOOTSTAGE_ID_NET_NETLOOP_OK);/* NetLoop ok, update environment */netboot_update_env();/* done if no file was loaded (no errors though) */if (size == 0) {bootstage_error(BOOTSTAGE_ID_NET_LOADED);return 0;}if (rcode < 0)bootstage_error(BOOTSTAGE_ID_NET_DONE_ERR);elsebootstage_mark(BOOTSTAGE_ID_NET_DONE);return rcode;
}

这个函数调用了net/net.c中的net_loop()函数,到这里本路径下的修改工作已完成。跳转到net/net.c中,在netloop函数的switch中添加case:UDP

#ifdef CONFIG_CMD_TFTPSRVcase TFTPSRV:TftpStartServer();break;
#endifcase UDP:UdpStart();            //my udpbreak;#if defined(CONFIG_CMD_DHCP)case DHCP:BootpReset();NetOurIP = 0;DhcpRequest();          /* Basically same as BOOTP */break;
#endif

还需要在include/net.h中添加UDP协议的声明

注意在net.h中要声明该变量是定义在别处的,这样编译器就能知道pkt_data(用来接终端输入的待传数据的)是一个在其他地方定义的全局变量,从而允许在common.c中正确地访问和使用这个变量。

至此UDP协议支持的相关配置工作已经完成,接下来要自己在net目录下写一个UDP协议的服务函数udp.c和udp.h

#include <common.h>
#include <command.h>
#include <net.h>
#include "tftp.h"
#include "bootp.h"
#include <flash.h>
#include "udp.h"uchar *pkt_data;
static int UdpPktLen;static IPaddr_t UdpServerIP;
static int      UdpServerPort;          /* The UDP port at their end            */
static int      UdpOurPort;             /* The UDP port at our end              */
static int      UdpTimeoutCount;static void UdpSend (void);/**********************************************************************/static void UdpSend (void)
{uchar *pkt;           //指向待发送数据包的指针int len = 0;          //数据包长度pkt = NetTxPacket + NetEthHdrSize() + IP_UDP_HDR_SIZE;
//      printf("NetEthHdrSize() = %d\n", NetEthHdrSize());
//      printf("IP_UDP_HDR_SIZE = %d\n", IP_UDP_HDR_SIZE);len = strlen(pkt_data);memcpy(pkt, pkt_data, len);printf("pkt_data = %s,len = %d\n", pkt_data, len);
//      printf("pkt = %s\n", pkt);NetSendUDPPacket(NetServerEther, UdpServerIP, UdpServerPort, UdpOurPort, len);
}static void UdpHandler (uchar *pkt, unsigned dest, IPaddr_t UdpServerIP, unsigned src, unsigned len)
{printf("---- receive udp packet ----\n");printf("len = %d\n",len);printf("data = %s\n", pkt);UdpSendAck();
}void UdpStart (void)
{char *ep;             /* Environment pointer */if ((ep = getenv("serverip")) != NULL){printf("ep = %s\n", ep);UdpServerIP = string_to_ip((const char *)ep);}#if defined(CONFIG_NET_MULTI)printf ("Using %s device\n", eth_get_name());
#endifnet_set_udp_handler(UdpHandler);        // 设置UDP数据包处理函数为UdpHandlerUdpServerPort = 50000;      //主机端口号;UdpOurPort = 30000;memset(NetServerEther, 0, 6);   //如果服务器IP地址发生了变化,清零服务器以太网地址(MAC地址)UdpSend ();
}
#ifndef __UDP_H__
#define __UDP_H__extern void UdpStart (void);#endif

别忘了在net目录下的Makefile中添加编译依赖项,保证udp.c被编译进镜像文件

至此uboot源码中的相关工作已经完成,接下来进行调试验证

写两个上位机程序来进行数据的收和发

#include <stdio.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <string.h>
#include <arpa/inet.h>
#include <unistd.h>
int main(void)
{int sockfd = 0;char tmpbuff[1024] = {0};struct sockaddr_in recvaddr;size_t nsize = 0;int ret = 0;sockfd = socket(AF_INET, SOCK_DGRAM, 0);if (-1 == sockfd){perror("fail to socket\n");return -1;}recvaddr.sin_family = AF_INET;recvaddr.sin_port = htons(50000);recvaddr.sin_addr.s_addr = INADDR_ANY;ret = bind(sockfd, (struct sockaddr *)&recvaddr, sizeof(recvaddr));if (ret == -1){perror("fail to bind");return -1;}nsize = recvfrom(sockfd, tmpbuff, sizeof(tmpbuff), 0, NULL, NULL);if (nsize == -1){perror("fail to recvfrom");return -1;}printf("接收  %ld 个字节\n", nsize);printf("Recv: %s\n", tmpbuff);close(sockfd);
}

#include <stdio.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <string.h>
#include <arpa/inet.h>
#include <unistd.h>
int main(void)
{int sockfd = 0;char tmpbuff[1024] = {0};struct sockaddr_in recvaddr;size_t nsize = 0;sockfd = socket(AF_INET, SOCK_DGRAM, 0);if (-1 == sockfd){perror("fail to socket\n");return -1;}gets(tmpbuff, strlen(tmpbuff), stdin);recvaddr.sin_family = AF_INET;recvaddr.sin_port = htons(30000);recvaddr.sin_addr.s_addr = inet_addr("172.31.13.207");nsize = sendto(sockfd, tmpbuff, strlen(tmpbuff), 0, (struct sockaddr *)&recvaddr, sizeof(recvaddr));if (nsize == -1){perror("fail to sendto");return -1;}printf("发送 %ld 个字节\n", nsize);close(sockfd);
}

三、测试

在uboot中发,上位机来收

在上位机中发,uboot中来收

极限性能测试

测试验证发发现,在不经过网络转发设备的前提下能跑满UDP协议理论最大包长1472字节。

四、补充说明

        以上只是简单在uboot中走通了UDP协议,故代码中不涉及待传数据的帧格式设计、重传机制、超时机制等,若要实现基于UDP协议自定义通信协议,还需要设计好以上几点。这个后面再说。

        注:uboot版本为2017年

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

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

相关文章

2024生成式AI商业落地白皮书_火山引擎

更多详细内容请下载资源 2024生成式AI商业落地白皮书-火山引擎

基于Python的mediapipe和opencv的人体骨骼、人体姿态关键点的实时跟踪项目

随着计算机视觉技术的发展&#xff0c;人体姿态估计在虚拟现实、运动分析、人机交互等领域得到了广泛应用。传统的姿态估计方法通常依赖于深度学习模型&#xff0c;需要大量的计算资源。而 Google 开发的 MediaPipe 框架则提供了高效且易于使用的解决方案&#xff0c;它可以在各…

Leetcode 237.19.83.82 删除链表重复结点 C++实现

Leetcode 237. 删除链表中的节点 问题&#xff1a;有一个单链表的head&#xff0c;我们想删除它其中的一个节点node。给你一个需要删除的节点 node 。你将 无法访问 第一个节点head。链表的所有值都是唯一的&#xff0c;并且保证给定的节点 node不是链表中的最后一个节点。删除…

重磅!RISC-V+OpenHarmony平板电脑发布

仟江水商业电讯&#xff08;8月18日 北京 委托发布&#xff09;RISC-V作为历史上全球发展速度最快、创新最为活跃的开放指令架构&#xff0c;正在不断拓展高性能计算领域的边界。OpenHarmony是由开放原子开源基金会孵化并运营的开源项目&#xff0c;已成为发展速度最快的智能终…

【机器学习】逻辑回归原理(极大似然估计,逻辑函数Sigmod函数模型详解!!!)

目录 &#x1f354; 逻辑回归应用场景 &#x1f354; 极大似然估计 2.1 为什么要有极大似然估计&#xff1f; 2.2 极大似然估计步骤 2.3 极大似然估计的例子 &#x1f354; Sigmod函数模型 3.1 逻辑斯特函数的由来 3.2 Sigmod函数绘图 3.3 进一步探究-加入线性回归 3…

OW-VISCap——开放世界视频实例分割方法研究

概述 论文地址&#xff1a;https://arxiv.org/pdf/2404.03657 本文提出了一种名为 OW-VISCap&#xff08;开放世界视频实例分割和字幕&#xff09;的方法。其三大贡献是 开放世界对象查询&#xff1a;除了已知对象查询外&#xff0c;还引入了开放世界对象查询&#xff0c;以发…

专题---自底向上的计算机网络(计算机网络相关概述)

目录 计算机网络相关概述 物理层 数据链路层 网络层 运输层 应用层 网络安全 1.计算机网络相关概述&#xff08;具体细节http://t.csdnimg.cn/NITAW&#xff09; 什么是计算机网络&#xff1f; 计算机网络是将一个分散的&#xff0c;具有独立功能的计算机系统&#x…

jmeter中添加ip欺骗

1、首先在本机电脑中通过配置文件创建添加ip的配置文件&#xff0c;先创建一个txt格式的&#xff0c;直接修改文件名以及后缀为ips.bat 2、编辑该ips.bat文件&#xff0c;在文件中输入如下内容&#xff0c;用于快速给本机添加ip地址&#xff0c;&#xff08;2&#xff0c;1&…

四川正信法律:男朋友借钱拉黑我了怎么办

在情感的海洋中&#xff0c;我们或许都曾遇到过打着爱情旗号的骗局。当男朋友借钱后选择拉黑&#xff0c;这不仅是物质上的损失&#xff0c;更是心灵上的重创。面对这样的困境&#xff0c;我们该如何应对? 面对现实&#xff0c;接受这一切的发生。痛苦与愤怒虽为正常反应&…

【MySQL】JDBC的基础使用

系列文章目录 第一章 数据库基础 第二章 数据库基本操作 第三章数据库约束 第四章表的设计 第五章查询进阶 第六章索引和事务 文章目录 系列文章目录前言一、JDBC基本概念二、JDBC的准备工作三、JDBC-Demo小结 四、JDBC进阶写法总结 前言 在前面对MySQL已经有了基本的认知&am…

状态dp或滑动窗口

前言&#xff1a;这个题目可以用状态dp来做&#xff0c;其实还有一个思路&#xff0c;类似滑动窗口&#xff0c;如果有遇到第二个0&#xff0c;左指针加一 class Solution { public:int longestSubarray(vector<int>& nums) {int n nums.size();vector<vector<…

2024年【起重信号司索工(建筑特殊工种)】考试题及起重信号司索工(建筑特殊工种)免费试题

题库来源&#xff1a;安全生产模拟考试一点通公众号小程序 起重信号司索工(建筑特殊工种)考试题是安全生产模拟考试一点通总题库中生成的一套起重信号司索工(建筑特殊工种)免费试题&#xff0c;安全生产模拟考试一点通上起重信号司索工(建筑特殊工种)作业手机同步练习。2024年…

洛谷 P4516 [JSOI2018] 潜入行动

题目来源于&#xff1a;洛谷 题目本质&#xff1a;背包&#xff0c;树形dp 解题思路&#xff1a; 假设当前合并两个背包f[u][a][p1][q1] 和f[v][b][p2][q2] &#xff0c;其中 v 是 u 的儿子。考虑合并后的f[u][ab][p3][q3],q3 是合并后点 u 是否被监听&#xff0c;有两种情况…

使用Java往Geoserver发布tif图层和shp图层

1. Maven依赖 栅格文件对应Tif文件 (即: 栅格就是tif) 矢量文件对应shp文件(即: 矢量就是shp) 注: 有的依赖可能在中央仓库及一些镜像仓库找不到需要手动指定仓库, 在依赖最下方 <!-- 中文转拼音工具类 --><dependency><groupId>com.belerweb</groupId&g…

简单步骤获取IP地址SSL 证书

在网络安全中&#xff0c;SSL证书在保护用户浏览器和Web服务器之间交换的敏感信息方面发挥着至关重要的作用。 但是&#xff0c;如果您不仅想保护域名&#xff0c;还想保护特定的IP地址&#xff0c;该怎么办&#xff1f;您可以为IP地址获取SSL证书吗&#xff1f; 简短的回答是…

.NET COER+CONSUL微服务项目在CENTOS环境下的部署实践

一、整体的环境安装与部署 1.1、DOCKER环境的部署 1.1.1 安装DOCKER yum install -y yum-utils device-mapper-persistent-data lvm2 yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo yum makecache fast && yu…

2024年【甘肃省安全员C证】考试题及甘肃省安全员C证考试总结

题库来源&#xff1a;安全生产模拟考试一点通公众号小程序 甘肃省安全员C证考试题考前必练&#xff01;安全生产模拟考试一点通每个月更新甘肃省安全员C证考试总结题目及答案&#xff01;多做几遍&#xff0c;其实通过甘肃省安全员C证模拟试题很简单。 1、【多选题】《安全生产…

企业要部署多点组网应该怎么做?

企业在进行扩张后&#xff0c;往往有建立多点组网的需求。本文将详细介绍企业怎样实现多点组网&#xff0c;以便有需要的用户进行了解和选择。 企业想要实现企业多点组网时&#xff0c;首先需要进行全面的网络规划和设计。这包括评估公司当前的网络架构、各个分支机构的地理位置…

AOP+ 自定义注解 +SpringElExpress自研缓存组件

AOP 自定义注解 SpringElExpress自研缓存组件 背景前置知识改造代码 背景 思考下这段代码&#xff0c;想想项目中是不是到处存在 先查缓存&#xff0c;缓存里面有&#xff0c;直接返回&#xff1b;缓存没有&#xff0c;查数据库&#xff0c;并更新到缓存 思考&#xff1a;如何…

区块链知识体系fisco-bcos实战

文章目录 一、区块链发展概述及类型和特征1.1 区块链的概念1.2 区块链的起源1.3 区块链的发展历程1.4 区块链的类型和特征 二、区块链的常见技术架构2.1 技术架构2.2 核心技术 三、区块链的常见应用3.1 生态环境监测3.2 医疗废弃物追踪解决3.3 区块链在电子政务领域的应用3.4 在…