当前位置: 首页 > article >正文

八、【ESP32开发全栈指南:UDP客户端】

1. 环境准备

  • 安装ESP-IDF v4.4+ (官方指南)
  • 确保Python 3.7+ 和Git已安装

2. 创建项目

idf.py create-project udp_client
cd udp_client

3. 完整优化代码 (main/main.c)

#include <string.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/event_groups.h"
#include "esp_wifi.h"
#include "esp_event.h"
#include "esp_log.h"
#include "esp_system.h"
#include "nvs_flash.h"
#include "lwip/err.h"
#include "lwip/sockets.h"
#include "lwip/sys.h"
#include <lwip/netdb.h>// 配置区 ========================================
#define WIFI_SSID       "YOUR_WIFI_SSID"
#define WIFI_PASS       "YOUR_WIFI_PASSWORD"
#define SERVER_IP       "192.168.1.100"  // 目标服务器IP
#define SERVER_PORT     8888             // 目标端口
#define MAX_RETRY       5                // WiFi最大重连次数
// ===============================================static const char *TAG = "UDP_Client";
static EventGroupHandle_t s_wifi_event_group;
static int s_retry_num = 0;/* 事件组位定义 */
#define WIFI_CONNECTED_BIT BIT0
#define WIFI_FAIL_BIT      BIT1// WiFi事件处理函数
static void event_handler(void* arg, esp_event_base_t event_base, int32_t event_id, void* event_data) {if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_START) {esp_wifi_connect();} else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_DISCONNECTED) {if (s_retry_num < MAX_RETRY) {esp_wifi_connect();s_retry_num++;ESP_LOGI(TAG, "Retry connecting to AP. Attempt %d/%d", s_retry_num, MAX_RETRY);} else {xEventGroupSetBits(s_wifi_event_group, WIFI_FAIL_BIT);ESP_LOGE(TAG, "Failed to connect after %d attempts", MAX_RETRY);}} else if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP) {ip_event_got_ip_t* event = (ip_event_got_ip_t*) event_data;ESP_LOGI(TAG, "Got IP: " IPSTR, IP2STR(&event->ip_info.ip));s_retry_num = 0;xEventGroupSetBits(s_wifi_event_group, WIFI_CONNECTED_BIT);}
}// WiFi初始化
void wifi_init_sta(void) {s_wifi_event_group = xEventGroupCreate();ESP_ERROR_CHECK(esp_netif_init());ESP_ERROR_CHECK(esp_event_loop_create_default());esp_netif_t *sta_netif = esp_netif_create_default_wifi_sta();wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();ESP_ERROR_CHECK(esp_wifi_init(&cfg));// 注册事件处理器esp_event_handler_instance_t instance_any_id;esp_event_handler_instance_t instance_got_ip;ESP_ERROR_CHECK(esp_event_handler_instance_register(WIFI_EVENT,ESP_EVENT_ANY_ID,&event_handler,NULL,&instance_any_id));ESP_ERROR_CHECK(esp_event_handler_instance_register(IP_EVENT,IP_EVENT_STA_GOT_IP,&event_handler,NULL,&instance_got_ip));// 配置WiFiwifi_config_t wifi_config = {.sta = {.ssid = WIFI_SSID,.password = WIFI_PASS,.threshold.authmode = WIFI_AUTH_WPA2_PSK,.pmf_cfg = {.capable = true,.required = false},},};ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA));ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_STA, &wifi_config));ESP_ERROR_CHECK(esp_wifi_start());ESP_LOGI(TAG, "WiFi initialization complete. Connecting to AP...");// 等待连接结果EventBits_t bits = xEventGroupWaitBits(s_wifi_event_group,WIFI_CONNECTED_BIT | WIFI_FAIL_BIT,pdFALSE,pdFALSE,portMAX_DELAY);if (bits & WIFI_CONNECTED_BIT) {ESP_LOGI(TAG, "Connected to AP SSID: %s", WIFI_SSID);} else if (bits & WIFI_FAIL_BIT) {ESP_LOGE(TAG, "Failed to connect to SSID: %s", WIFI_SSID);} else {ESP_LOGE(TAG, "Unexpected event");}// 清理事件组vEventGroupDelete(s_wifi_event_group);
}// UDP客户端任务
void udp_client_task(void *pvParameters) {ESP_LOGI(TAG, "Starting UDP client task");struct sockaddr_in dest_addr = {.sin_addr.s_addr = inet_addr(SERVER_IP),.sin_family = AF_INET,.sin_port = htons(SERVER_PORT)};char rx_buffer[128];char tx_buffer[50];char addr_str[INET_ADDRSTRLEN];inet_ntop(AF_INET, &dest_addr.sin_addr, addr_str, sizeof(addr_str));ESP_LOGI(TAG, "Target server: %s:%d", addr_str, SERVER_PORT);while (1) {int sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);if (sock < 0) {ESP_LOGE(TAG, "Failed to create socket: errno %d", errno);vTaskDelay(2000 / portTICK_PERIOD_MS);continue;}// 设置超时选项(2秒)struct timeval timeout = {.tv_sec = 2,.tv_usec = 0};setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout));// 发送数据snprintf(tx_buffer, sizeof(tx_buffer), "Hello #%d", (int)(xTaskGetTickCount()/1000));int err = sendto(sock, tx_buffer, strlen(tx_buffer), 0, (struct sockaddr *)&dest_addr, sizeof(dest_addr));if (err < 0) {ESP_LOGE(TAG, "Send error: errno %d", errno);close(sock);vTaskDelay(2000 / portTICK_PERIOD_MS);continue;}ESP_LOGI(TAG, "Sent: %s", tx_buffer);// 接收响应struct sockaddr_in source_addr;socklen_t addr_len = sizeof(source_addr);int len = recvfrom(sock, rx_buffer, sizeof(rx_buffer) - 1, 0, (struct sockaddr *)&source_addr, &addr_len);if (len > 0) {rx_buffer[len] = 0; // Null-terminateinet_ntop(AF_INET, &source_addr.sin_addr, addr_str, sizeof(addr_str));ESP_LOGI(TAG, "Received %d bytes from %s:%d", len, addr_str, ntohs(source_addr.sin_port));ESP_LOGI(TAG, "Data: %s", rx_buffer);} else if (len == 0) {ESP_LOGW(TAG, "Connection closed by server");} else {if (errno == EAGAIN || errno == EWOULDBLOCK) {ESP_LOGW(TAG, "Receive timeout");} else {ESP_LOGE(TAG, "Receive failed: errno %d", errno);}}close(sock);ESP_LOGI(TAG, "Next message in 3 seconds...");vTaskDelay(3000 / portTICK_PERIOD_MS);}vTaskDelete(NULL);
}void app_main() {// 初始化NVS存储esp_err_t ret = nvs_flash_init();if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {ESP_ERROR_CHECK(nvs_flash_erase());ret = nvs_flash_init();}ESP_ERROR_CHECK(ret);// 连接WiFiwifi_init_sta();// 启动UDP任务xTaskCreate(udp_client_task, "udp_client", 4096, NULL, 5, NULL);
}

4. 关键改进说明

  1. 健壮的错误处理

    • 添加了WiFi连接最大重试机制(MAX_RETRY
    • 完善的socket错误码处理
    • 接收超时设置(2秒)
  2. 网络优化

    • 使用inet_ntop替代已弃用的inet_ntoa
    • 设置SO_RCVTIMEO接收超时选项
    • 每次发送后关闭socket释放资源
  3. 增强可读性

    • 结构化日志输出
    • 动态生成测试消息(带时间戳)
    • 清晰的错误分类(ERROR/WARNING/INFO)
  4. 资源管理

    • 正确释放事件组资源
    • 安全的字符串处理(snprintf
    • 内存边界检查

5. 编译烧录

idf.py set-target esp32  # 根据实际芯片选择
idf.py build
idf.py -p /dev/ttyUSB0 flash monitor  # 替换实际串口

6. 测试服务器示例 (Python)

# UDP_test_server.py
import socketUDP_IP = "0.0.0.0"
UDP_PORT = 8888sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.bind((UDP_IP, UDP_PORT))print(f"Listening on {UDP_PORT}")
while True:data, addr = sock.recvfrom(1024)print(f"Received: {data.decode()} from {addr}")sock.sendto(b"ACK:" + data, addr)

7. 注意事项

  1. 配置修改

    • 替换YOUR_WIFI_SSIDYOUR_WIFI_PASSWORD
    • 根据网络环境修改SERVER_IP
    • 调整MAX_RETRY和超时时间
  2. 常见问题排查

    I (1845) UDP_Client: Got IP: 192.168.1.101
    I (1845) UDP_Client: Starting UDP client task
    I (1845) UDP_Client: Target server: 192.168.1.100:8888
    I (1855) UDP_Client: Sent: Hello #18
    W (2855) UDP_Client: Receive timeout
    
    • 检查服务器IP/端口是否正确
    • 确认服务器防火墙允许UDP流量
    • 使用Wireshark抓包验证网络连通性

相关文章:

八、【ESP32开发全栈指南:UDP客户端】

1. 环境准备 安装ESP-IDF v4.4 (官方指南)确保Python 3.7 和Git已安装 2. 创建项目 idf.py create-project udp_client cd udp_client3. 完整优化代码 (main/main.c) #include <string.h> #include "freertos/FreeRTOS.h" #include "freertos/task.h&…...

在MobaXterm 打开图形工具firefox

目录 1.安装 X 服务器软件 2.服务器端配置 3.客户端配置 4.安装并打开 Firefox 1.安装 X 服务器软件 Centos系统 # CentOS/RHEL 7 及之前&#xff08;YUM&#xff09; sudo yum install xorg-x11-server-Xorg xorg-x11-xinit xorg-x11-utils mesa-libEGL mesa-libGL mesa-…...

旋量理论:刚体运动的几何描述与机器人应用

旋量理论为描述刚体在三维空间中的运动提供了强大而优雅的数学框架。与传统的欧拉角或方向余弦矩阵相比&#xff0c;旋量理论通过螺旋运动的概念统一了旋转和平移&#xff0c;在机器人学、计算机图形学和多体动力学领域具有显著优势。这种描述不仅几何直观&#xff0c;而且计算…...

SE(Secure Element)加密芯片与MCU协同工作的典型流程

以下是SE&#xff08;Secure Element&#xff09;加密芯片与MCU协同工作的典型流程&#xff0c;综合安全认证、数据保护及防篡改机制&#xff1a; 一、基础认证流程&#xff08;参数保护方案&#xff09; 密钥预置‌ SE芯片与MCU分别预置相同的3DES密钥&#xff08;Key1、Key2…...

运动控制--BLDC电机

一、电机的分类 按照供电电源 1.直流电机 1.1 有刷直流电机(BDC) 通过电刷与换向器实现电流方向切换&#xff0c;典型应用于电动工具、玩具等 1.2 无刷直流电机&#xff08;BLDC&#xff09; 电子换向替代机械电刷&#xff0c;具有高可靠性&#xff0c;常用于无人机、高端家电…...

Redis专题-实战篇一-基于Session和Redis实现登录业务

GitHub项目地址&#xff1a;https://github.com/whltaoin/redisLearningProject_hm-dianping 基于Session实现登录业务功能提交版本码&#xff1a;e34399f 基于Redis实现登录业务提交版本码&#xff1a;60bf740 一、导入黑马点评后端项目 项目架构图 1. 前期阶段2. 后续阶段导…...

【前端实战】如何让用户回到上次阅读的位置?

目录 【前端实战】如何让用户回到上次阅读的位置&#xff1f; 一、总体思路 1、核心目标 2、涉及到的技术 二、实现方案详解 1、基础方法&#xff1a;监听滚动&#xff0c;记录 scrollTop&#xff08;不推荐&#xff09; 2、Intersection Observer 插入探针元素 3、基…...

dvwa11——XSS(Reflected)

LOW 分析源码&#xff1a;无过滤 和上一关一样&#xff0c;这一关在输入框内输入&#xff0c;成功回显 <script>alert(relee);</script> MEDIUM 分析源码&#xff0c;是把<script>替换成了空格&#xff0c;但没有禁用大写 改大写即可&#xff0c;注意函数…...

关于疲劳分析的各种方法

疲劳寿命预测方法很多。按疲劳裂纹形成寿命预测的基本假定和控制参数&#xff0c;可分为名义应力法、局部应力一应变法、能量法、场强法等。 1名义应力法 名义应力法是以结构的名义应力为试验和寿命估算的基础&#xff0c;采用雨流法取出一个个相互独立、互不相关的应力循环&…...

数据库优化实战指南:提升性能的黄金法则

在现代软件系统中&#xff0c;数据库性能直接影响应用的响应速度和用户体验。面对数据量激增、访问压力增大&#xff0c;数据库性能瓶颈经常成为项目痛点。如何科学有效地优化数据库&#xff0c;提升查询效率和系统稳定性&#xff0c;是每位开发与运维人员必备的技能。 本文结…...

【Axure高保真原型】图片列表添加和删除图片

今天和大家分享图片列表添加和删除图片的原型模板&#xff0c;效果包括&#xff1a; 点击图片列表的加号可以显示图片选择器&#xff0c;选择里面的图片&#xff1b; 选择图片后点击添加按钮&#xff0c;可以将该图片添加到图片列表&#xff1b; 鼠标移入图片列表的图片&…...

XXE漏洞知识

目录 1.XXE简介与危害 XML概念 XML与HTML的区别 1.pom.xml 主要作用 2.web.xml 3.mybatis 2.XXE概念与危害 案例&#xff1a;文件读取&#xff08;需要Apache >5.4版本&#xff09; 案例&#xff1a;内网探测&#xff08;鸡肋&#xff09; 案例&#xff1a;执行命…...

mq安装新版-3.13.7的安装

一、下载包&#xff0c;上传到服务器 https://github.com/rabbitmq/rabbitmq-server/releases/download/v3.13.7/rabbitmq-server-generic-unix-3.13.7.tar.xz 二、 erlang直接安装 rpm -ivh erlang-26.2.4-1.el8.x86_64.rpm不需要配置环境变量&#xff0c;直接就安装了。 erl…...

第21节 Node.js 多进程

Node.js本身是以单线程的模式运行的&#xff0c;但它使用的是事件驱动来处理并发&#xff0c;这样有助于我们在多核 cpu 的系统上创建多个子进程&#xff0c;从而提高性能。 每个子进程总是带有三个流对象&#xff1a;child.stdin, child.stdout和child.stderr。他们可能会共享…...

DL00871-基于深度学习YOLOv11的盲人障碍物目标检测含完整数据集

基于深度学习YOLOv11的盲人障碍物目标检测&#xff1a;开启盲人出行新纪元 在全球范围内&#xff0c;盲人及视觉障碍者的出行问题一直是社会关注的重点。尽管技术不断进步&#xff0c;许多城市的无障碍设施依然未能满足盲人出行的实际需求。尤其是在复杂的城市环境中&#xff…...

华硕电脑,全新的超频方式,无需进入BIOS

想要追求更佳性能释放 或探索更多可玩性的小伙伴&#xff0c; 可能会需要为你的电脑超频。 但我们常用的不论是BIOS里的超频&#xff0c; 还是Armoury Crate奥创智控中心超频&#xff0c; 每次调节都要重启&#xff0c;有点麻烦。 TurboV Core 全新的超频方案来了 4不规…...

安全领域新突破:可视化让隐患无处遁形

在安全领域&#xff0c;隐患就像暗处的 “幽灵”&#xff0c;随时可能引发严重事故。传统安全排查手段&#xff0c;常常难以将它们一网打尽。你是否好奇&#xff0c;究竟是什么神奇力量&#xff0c;能让这些潜藏的隐患无所遁形&#xff1f;没错&#xff0c;就是可视化技术。它如…...

触发DMA传输错误中断问题排查

在STM32项目中&#xff0c;集成BLE模块后触发DMA传输错误中断&#xff08;DMA2_Stream1_IRQHandler进入错误流程&#xff09;&#xff0c;但单独运行BLE模块时正常&#xff0c;表明问题可能源于原有线程与BLE模块的交互冲突。以下是逐步排查与解决方案&#xff1a; 一、问题根源…...

Vue.js教学第二十一章:vue实战项目二,个人博客搭建

基于 Vue 的个人博客网站搭建 摘要: 随着前端技术的不断发展,Vue 作为一种轻量级、高效的前端框架,为个人博客网站的搭建提供了极大的便利。本文详细介绍了基于 Vue 搭建个人博客网站的全过程,包括项目背景、技术选型、项目架构设计、功能模块实现、性能优化与测试等方面。…...

[KCTF]CORE CrackMe v2.0

这个Reverse比较古老&#xff0c;已经有20多年了&#xff0c;但难度确实不小。 先查壳 upx压缩壳&#xff0c;0.72&#xff0c;废弃版本&#xff0c;工具无法解压。 反正不用IDA进行调试&#xff0c;直接x32dbg中&#xff0c;dump内存&#xff0c;保存后拖入IDA。 这里说一下…...

Redis——Cluster配置

目录 分片 一、分片的本质与核心价值 二、分片实现方案对比 三、分片算法详解 1. ‌范围分片&#xff08;顺序分片&#xff09;‌ 2. ‌哈希分片‌ 3. ‌虚拟槽分片&#xff08;Redis Cluster 方案&#xff09;‌ 四、Redis Cluster 分片实践要点 五、经典问题解析 C…...

Ubuntu 安装 Mysql 数据库

首先更新apt-get工具&#xff0c;执行命令如下&#xff1a; apt-get upgrade安装Mysql&#xff0c;执行如下命令&#xff1a; apt-get install mysql-server 开启Mysql 服务&#xff0c;执行命令如下&#xff1a; service mysql start并确认是否成功开启mysql,执行命令如下&am…...

结合PDE反应扩散方程与物理信息神经网络(PINN)进行稀疏数据预测的技术方案

以下是一个结合PDE反应扩散方程与物理信息神经网络(PINN)进行稀疏数据预测的技术方案,包含完整数学推导、PyTorch/TensorFlow双框架实现代码及对比实验分析。 基于PINN的反应扩散方程稀疏数据预测与大规模数据泛化能力研究 1. 问题定义与数学模型 1.1 反应扩散方程 考虑标…...

从0开始一篇文章学习Nginx

Nginx服务 HTTP介绍 ## HTTP协议是Hyper Text Transfer Protocol&#xff08;超文本传输协议&#xff09;的缩写,是用于从万维网&#xff08;WWW:World Wide Web &#xff09;服务器传输超文本到本地浏览器的传送协议。 ## HTTP工作在 TCP/IP协议体系中的TCP协议上&#…...

Java高级 |【实验八】springboot 使用Websocket

隶属文章&#xff1a;Java高级 | &#xff08;二十二&#xff09;Java常用类库-CSDN博客 系列文章&#xff1a;Java高级 | 【实验一】Springboot安装及测试 |最新-CSDN博客 Java高级 | 【实验二】Springboot 控制器类相关注解知识-CSDN博客 Java高级 | 【实验三】Springboot 静…...

scan_mode设计原则

scan_mode设计原则 在进行mtp controller设计时&#xff0c;基本功能设计完成后&#xff0c;需要设计scan_mode设计。 1、在进行scan_mode设计时&#xff0c;需要保证mtp处于standby模式&#xff0c;不会有擦写、编程动作。 2、只需要固定mtp datasheet说明的接口即可&#xf…...

设计模式-3 行为型模式

一、观察者模式 1、定义 定义对象之间的一对多的依赖关系&#xff0c;这样当一个对象改变状态时&#xff0c;它的所有依赖项都会自动得到通知和更新。 描述复杂的流程控制 描述多个类或者对象之间怎样互相协作共同完成单个对象都无法单独度完成的任务 它涉及算法与对象间职责…...

qt 双缓冲案例对比

双缓冲 1.双缓冲原理 单缓冲&#xff1a;在paintEvent中直接绘制到屏幕&#xff0c;绘制过程被用户看到 双缓冲&#xff1a;先在redrawBuffer绘制到缓冲区&#xff0c;然后一次性显示完整结果 代码结构 单缓冲&#xff1a;所有绘制逻辑在paintEvent中 双缓冲&#xff1a;绘制…...

2025年全国I卷数学压轴题解答

第19题第3问: b b b 使得存在 t t t, 对于任意的 x x x, 5 cos ⁡ x − cos ⁡ ( 5 x t ) < b 5\cos x-\cos(5xt)<b 5cosx−cos(5xt)<b, 求 b b b 的最小值. 解: b b b 的最小值 b m i n min ⁡ t max ⁡ x g ( x , t ) b_{min}\min_{t} \max_{x} g(x,t) bmi…...

JS设计模式(5): 发布订阅模式

解锁JavaScript发布订阅模式&#xff1a;让代码沟通更优雅 在JavaScript的世界里&#xff0c;我们常常会遇到这样的场景&#xff1a;多个模块之间需要相互通信&#xff0c;但是又不想让它们产生过于紧密的耦合。这时候&#xff0c;发布订阅模式就像一位优雅的信使&#xff0c;…...