八、【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抓包验证网络连通性

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

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

相关文章

Android Studio 解决首次安装时下载 Gradle 慢问题

1、问题描述 第一次安装 Android Studio 时&#xff0c; 新建工程后&#xff0c;在编译时会自动去下载 Gradle&#xff0c;但是一般都会下载失败&#xff0c;提示链接超时&#xff1a; Could not install Gradle distribution from https://services.gradle.org/distributions…

hive聚合函数多行合并

在数据仓库和大数据处理的场景中&#xff0c;Hive提供了强大的SQL查询能力&#xff0c;其中包括聚合函数用于处理和合并多行数据。本文将深入探讨Hive中的几种常见聚合函数及其在多行合并中的应用。 一、Hive中的常见聚合函数 Hive提供了多种聚合函数&#xff0c;这些函数可以…

关于物联网的基础知识(一)

成长路上不孤单&#x1f60a;&#x1f60a;&#x1f60a;&#x1f60a;&#x1f60a;&#x1f60a; 【14后&#x1f60a;///计算机爱好者&#x1f60a;///持续分享所学&#x1f60a;///如有需要欢迎收藏转发///&#x1f60a;】 今日分享关于物联网的基础知识&#xff08;一&a…

迁移科技3D视觉系统:重塑纸箱拆垛场景的智能革命

一、传统拆垛场景的困局与破局之道 在汽车零部件仓库中&#xff0c;每天有超过2万只异形纸箱需要拆垛分拣。传统人工拆垛面临三大挑战&#xff1a; 效率瓶颈&#xff1a;工人每小时仅能处理200-300件&#xff0c;且存在间歇性疲劳安全隐患&#xff1a;20kg以上重箱搬运导致年…

微软重磅发布Magentic UI,交互式AI Agent助手实测!

微软重磅发布Magentic UI,交互式AI Agent助手实测! 何为Magentic UI? Magentic UI 是微软于5.19重磅发布的开源Agent助手,并于24日刚更新了第二个版本0.04版 从官方的介绍来看,目标是打造一款 以人为中心 的智能助手,其底层由多个不同的智能体系统驱动,能够实现网页浏览…

Python实现快速排序的三种经典写法及算法解析

今天想熟悉一下python的基础写法&#xff0c;那就从最经典的快速排序来开始吧&#xff1a; 1、经典分治写法&#xff08;原地排序&#xff09; 时间复杂度&#xff1a;平均O(nlogn)&#xff0c;最坏O(n) 空间复杂度&#xff1a;O(logn)递归栈空间 特点&#xff1a;通过左右指针…

海康网络摄像头实时取帧转Opencv数组格式(h,w,3),已实现python、C#

海康摄像头取帧都是有官方demo的&#xff0c;但是将海康格式的数据转为Opencv格式的没有相关demo&#xff0c;而大部分深度学习图像检测算法(如YOLO)&#xff0c;都是用opencv格式的图像作为输入&#xff0c;因此将海康格式数据转为opencv格式兼容性更强 需要代码请私信联系&a…

职坐标IT教育物联网全栈开发实战:传感器到云平台全链路

物联网全栈开发涉及从终端感知到云端服务的全流程技术整合&#xff0c;其核心在于构建完整的“端-管-云-用”技术链条。为帮助开发者系统掌握这一能力&#xff0c;课程围绕四大模块展开&#xff1a;传感器数据采集与处理、通信协议适配与优化、云平台架构设计及跨平台应用开发。…

LUFFY(路飞): 使用DeepSeek指导Qwen强化学习

论文标题 Learning to Reason under Off-Policy Guidance 论文地址 https://arxiv.org/pdf/2504.14945 代码地址 https://github.com/ElliottYan/LUFFY 作者背景 上海人工智能实验室&#xff0c;西湖大学&#xff0c;南京大学&#xff0c;香港中文大学 动机 目前大模型…

Android Camera Hal中通过Neon指令优化数据拷贝

背景描述&#xff1a; Camera apk普通相机模式录像操作时&#xff0c;一般是同时请求两个流&#xff0c;即预览流和录像流。对于两个流输出图像格式和分辨率相同的情况下&#xff0c;是不是可以通过一个流拷贝得到另一个流的数据&#xff0c;进而节省掉一个Sensor输出处理两次…

WPS word 已有多级列表序号

wps的word中&#xff0c;原来已生成的文档里&#xff0c;已存在序号。比如&#xff0c;存在2、2.1、2.1.1、2.1.1.1、2.1.1.1.1 5层序号&#xff0c;而且已分为5级。但增加内容的时候&#xff0c;并不会自动增加序号&#xff0c;应该如何解决&#xff1f; 原来长这样&#xff…

从零开始制作小程序简单概述

以下是结合案例的“从零制作小红书风格小程序”的全流程指南&#xff0c;采用小红书爆款笔记的结构呈现&#xff0c;并附CSDN参考资源&#x1f447;&#xff1a; 一、核心开发步骤&#xff08;附工具推荐&#xff09; 账号与定位 ✅ 注册类型选择&#xff1a;个人店&#xff08…

【Go语言基础【13】】函数、闭包、方法

文章目录 零、概述一、函数基础1、函数基础概念2、参数传递机制3、返回值特性3.1. 多返回值3.2. 命名返回值3.3. 错误处理 二、函数类型与高阶函数1. 函数类型定义2. 高阶函数&#xff08;函数作为参数、返回值&#xff09; 三、匿名函数与闭包1. 匿名函数&#xff08;Lambda函…

网络编程之服务器模型与UDP编程

一、服务器模型 在网络通信中&#xff0c;通常要求一个服务器连接多个客户端 为了处理多个客户端的请求&#xff0c;通常有多种表现形式 1、循环服务器模型 一个服务器可以连接多个客户端&#xff0c;但同一时间只能连接并处理一个客户的请求 socket() 结构体 bind() listen() …

open3D:三维点云处理

open3d 点云数据处理 爆肝5万字❤️Open3D 点云数据处理基础&#xff08;Python版&#xff09;_python 点云 焊缝-CSDN博客 如何用NumPy读取和保存点云数据 - 知乎 读取并可视化点云 np.loadtxt 从txt中读取点集&#xff0c;并open3d显示单个点云 txt内容&#xff1a;每行皆…

使用联邦多轨迹图神经网络(GNNs)结合稀缺数据预测婴儿脑连接|文献速递-深度学习医疗AI最新文献

Title 题目 Predicting infant brain connectivity with federated multi-trajectory GNNs using scarce data 使用联邦多轨迹图神经网络&#xff08;GNNs&#xff09;结合稀缺数据预测婴儿脑连接 01 文献速递介绍 多模态影像下的婴儿脑连接演化预测&#xff1a;联邦学习与…

[特殊字符] 深入理解 Linux 内核进程管理:架构、核心函数与调度机制

Linux 内核作为一个多任务操作系统&#xff0c;其进程管理子系统是核心组成部分之一。无论是用户应用的运行、驱动行为的触发&#xff0c;还是系统调度决策&#xff0c;几乎所有操作都离不开进程的创建、调度与销毁。本文将从进程的概念出发&#xff0c;深入探讨 Linux 内核中进…

第16节 Node.js 文件系统

Node.js 提供一组类似 UNIX&#xff08;POSIX&#xff09;标准的文件操作API。 Node 导入文件系统模块(fs)语法如下所示&#xff1a; var fs require("fs") 异步和同步 Node.js 文件系统&#xff08;fs 模块&#xff09;模块中的方法均有异步和同步版本&#xff…

《探秘局域网广播:网络世界的 “大喇叭”》

揭开局域网广播的神秘面纱 在当今数字化时代,网络已成为人们生活和工作中不可或缺的一部分。从日常的网页浏览、社交媒体互动,到企业级的数据传输、云计算应用,网络通信无处不在。在这个庞大而复杂的网络世界里,数据如同信息流在各个节点之间穿梭,而局域网广播则是其中一种…

基于Ubuntu22.04安装SVN服务器之仓库迁移

基于Ubuntu22.04安装SVN服务器之仓库迁移 第一步: 停止svn服务器 第一步: 停止svn服务器 1&#xff09;建议迁移的时候先把SN服务器停掉&#xff0c;以免操作失败。 svnserve -d -r /usr/svn第二步&#xff1a;dump出svn代码库 1&#xff09;通过dump出旧的svn服务器上的代码…