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

八、【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.lqws.cn/news/207397.html

相关文章:

  • CSS 预处理器与工具
  • 1.4 Node.js 的 TCP 和 UDP
  • [HCTF 2018]admin 1
  • n8n + AI Agent:AI 自动化生成测试用例并支持导出 Excel
  • NPOI Excel用OLE对象的形式插入文件附件以及插入图片
  • Model Context Protocol (MCP) 是一个前沿框架
  • 多文化软件团队的协作之道:在认知差异中寻找协同的支点
  • 基于Scala实现Flink的三种基本时间窗口操作
  • 20250607-在Ubuntu中使用Anaconda创建新环境并使用本地的备份文件yaml进行配置
  • 网络协议通俗易懂详解指南
  • 交叉熵损失函数和极大似然估计是什么,区别是什么
  • 【数据结构初阶】--算法复杂度的深度解析
  • Canal环境搭建并实现和ES数据同步
  • Web前端基础:JavaScript
  • Go语言堆内存管理
  • 设计模式-建造者模式
  • 备份还原打印机驱动
  • Linux【4】------RK3568启动和引导顺序
  • grep、wc 与管道符快速上手指南
  • 10.Linux进程信号
  • 运维_集运维核心学习
  • ASTRA论文总结
  • Android Studio 解决首次安装时下载 Gradle 慢问题
  • TCP/IP 与高速网络
  • 基于Java Swing的固定资产管理系统设计与实现:附完整源码与论文
  • EMD算法
  • aws(学习笔记第四十三课) s3_sns_sqs_lambda_chain
  • VSCode CUDA C++进行Linux远程开发
  • 【数据结构】详解算法复杂度:时间复杂度和空间复杂度
  • R语言AI模型部署方案:精准离线运行详解