十、【ESP32开发全栈指南: TCP客户端】
一、TCP协议核心特性回顾
TCP与UDP关键差异
特性 | TCP | UDP |
---|---|---|
连接方式 | 面向连接 (三次握手) | 无连接 |
可靠性 | 可靠传输 (重传/排序/校验) | 尽力交付 |
数据顺序 | 保证数据按序到达 | 不保证顺序 |
流控制 | 滑动窗口机制 | 无流控制 |
传输效率 | 协议开销大 | 头部开销小 |
适用场景 | 文件传输、网页浏览 | 实时音视频、广播通信 |
📌 ESP32应用场景:OTA固件升级(TCP)、传感器数据上报(UDP)、远程控制(TCP)
二、ESP32网络架构
-
lwIP轻量级TCP/IP栈
- ESP-IDF定制版本:
esp-lwip
- 支持全功能BSD Socket API
- 默认启用TCP/IP协议栈
- ESP-IDF定制版本:
-
核心组件
- ESP-NETIF:网络接口抽象层
- 事件循环:处理网络事件
- 协议栈配置:通过menuconfig调整
三、TCP客户端开发流程
3.1 工作流程
3.2 代码实现详解
// 创建TCP客户端
void tcp_client_task(void *pvParameters) {// 1. 创建套接字int sock = socket(AF_INET, SOCK_STREAM, IPPROTO_IP);if (sock < 0) {ESP_LOGE(TAG, "创建套接字失败: errno %d", errno);vTaskDelete(NULL);}// 2. 配置服务器地址struct sockaddr_in server_addr = {.sin_family = AF_INET,.sin_port = htons(CONFIG_TARGET_PORT),.sin_addr.s_addr = inet_addr(CONFIG_TARGET_IP)};// 3. 连接服务器int retry_count = 0;while (connect(sock, (struct sockaddr *)&server_addr, sizeof(server_addr)) != 0) {if (++retry_count > 5) {ESP_LOGE(TAG, "连接失败, 错误码: %d", errno);close(sock);vTaskDelete(NULL);}vTaskDelay(2000 / portTICK_PERIOD_MS);}ESP_LOGI(TAG, "成功连接到服务器 %s:%d", CONFIG_TARGET_IP, CONFIG_TARGET_PORT);// 4. 数据交换循环char rx_buffer[128];while (1) {// 发送数据const char *payload = "ESP32心跳";if (send(sock, payload, strlen(payload), 0) < 0) {ESP_LOGE(TAG, "发送失败: %d", errno);break;}// 接收数据 (带超时设置)struct timeval tv = { .tv_sec = 10 };setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv));int len = recv(sock, rx_buffer, sizeof(rx_buffer)-1, 0);if (len > 0) {rx_buffer[len] = '\0';ESP_LOGI(TAG, "收到 %d 字节: %s", len, rx_buffer);} else if (len == 0) {ESP_LOGW(TAG, "连接被服务器关闭");break;} else {ESP_LOGE(TAG, "接收错误: %d", errno);break;}vTaskDelay(5000 / portTICK_PERIOD_MS);}// 5. 清理资源shutdown(sock, 0);close(sock);vTaskDelete(NULL);
}
3.3 关键函数解析
-
socket()
AF_INET
:IPv4协议族SOCK_STREAM
:流式套接字(TCP)- 返回值:套接字描述符(负数为错误)
-
connect()
- 阻塞式连接(默认)
- 可设置非阻塞模式:
fcntl(sock, F_SETFL, O_NONBLOCK);
-
send()/recv()
- 面向连接的数据传输
- 注意处理部分发送/接收情况
四、WiFi连接模式
4.1 Station模式(直连路由器)
void wifi_init_sta() {// 标准初始化流程ESP_ERROR_CHECK(esp_netif_init());ESP_ERROR_CHECK(esp_event_loop_create_default());esp_netif_create_default_wifi_sta();wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();ESP_ERROR_CHECK(esp_wifi_init(&cfg));// 配置WiFi参数wifi_config_t wifi_config = {.sta = {.ssid = CONFIG_WIFI_SSID,.password = CONFIG_WIFI_PASSWORD}};ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA));ESP_ERROR_CHECK(esp_wifi_set_config(ESP_IF_WIFI_STA, &wifi_config));ESP_ERROR_CHECK(esp_wifi_start());ESP_ERROR_CHECK(esp_wifi_connect());
}
4.2 SmartConfig配网模式
实现关键点:
// SmartConfig事件处理
static void sc_event_handler(void* arg, esp_event_base_t base, int32_t id, void* data) {if (id == SC_EVENT_GOT_SSID_PSWD) {// 提取配置信息smartconfig_event_got_ssid_pswd_t *evt = data;// 配置WiFiwifi_config_t wifi_config = {0};memcpy(wifi_config.sta.ssid, evt->ssid, sizeof(evt->ssid));memcpy(wifi_config.sta.password, evt->password, sizeof(evt->password));ESP_ERROR_CHECK(esp_wifi_set_config(ESP_IF_WIFI_STA, &wifi_config));ESP_ERROR_CHECK(esp_wifi_connect());}else if (id == SC_EVENT_SEND_ACK_DONE) {// 启动TCP客户端任务xTaskCreate(tcp_client_task, "tcp_client", 4096, NULL, 5, NULL);}
}
五、高级功能与优化
5.1 连接保活机制
// 启用TCP Keepalive
int keepalive_enable = 1;
int keepalive_idle = 30; // 30秒无活动发送探测
int keepalive_interval = 5; // 探测间隔
int keepalive_count = 3; // 最大探测次数setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, &keepalive_enable, sizeof(int));
setsockopt(sock, IPPROTO_TCP, TCP_KEEPIDLE, &keepalive_idle, sizeof(int));
setsockopt(sock, IPPROTO_TCP, TCP_KEEPINTVL, &keepalive_interval, sizeof(int));
setsockopt(sock, IPPROTO_TCP, TCP_KEEPCNT, &keepalive_count, sizeof(int));
5.2 错误处理策略
-
连接失败:
- 检查网络状态
- 实现指数退避重连
int delay_ms = 1000; while (connect() != 0) {vTaskDelay(delay_ms / portTICK_PERIOD_MS);delay_ms *= 2; // 指数退避if (delay_ms > 30000) delay_ms = 30000; }
-
传输中断:
- 检测errno值
- 重建连接恢复传输
5.3 性能优化技巧
-
增大发送缓冲区:
int send_buf_size = 8192; setsockopt(sock, SOL_SOCKET, SO_SNDBUF, &send_buf_size, sizeof(send_buf_size));
-
使用Nagle算法:
int nagle_disable = 1; setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, &nagle_disable, sizeof(nagle_disable));
六、实战应用场景
6.1 固件OTA升级
6.2 远程设备控制
+----------+ +------------+ +----------+
| 手机APP | ---> | 云服务器 | ---> | ESP32设备|
| (控制指令)| | (TCP中转) | | (执行动作)|
+----------+ +------------+ +----------+
6.3 数据同步系统
void sync_data_to_server() {// 1. 建立TCP连接// 2. 发送本地存储的数据// 3. 接收服务器确认// 4. 标记已同步数据// 5. 保持长连接接收新指令
}
七、调试与问题排查
-
常见错误代码:
ECONNREFUSED
(111):服务器拒绝连接ETIMEDOUT
(110):连接超时ENOBUFS
(105):缓冲区不足ECONNRESET
(104):连接被重置
-
诊断工具:
- Wireshark抓包分析
- ESP-IDF内置网络调试工具:
idf.py monitor
- LwIP统计信息:
#include "lwip/stats.h" stats_display();
-
连接问题检查清单:
- WiFi是否连接成功
- 服务器IP和端口是否正确
- 防火墙是否放行端口
- 服务器应用是否运行
完整示例代码:ESP-IDF TCP客户端示例
通过本指南,您将掌握ESP32 TCP客户端开发的完整流程,从基础连接到高级优化,满足各类物联网应用的通信需求。
相关文章:
十、【ESP32开发全栈指南: TCP客户端】
一、TCP协议核心特性回顾 TCP与UDP关键差异 特性TCPUDP连接方式面向连接 (三次握手)无连接可靠性可靠传输 (重传/排序/校验)尽力交付数据顺序保证数据按序到达不保证顺序流控制滑动窗口机制无流控制传输效率协议开销大头部开销小适用场景文件传输、网页浏览实时音视频、广播通…...
基于机器学习的智能故障预测系统:构建与优化
前言 在现代工业生产中,设备故障不仅会导致生产中断,还会带来巨大的经济损失。传统的故障检测方法依赖于人工巡检和定期维护,这种方式效率低下且难以提前预测潜在故障。随着工业物联网(IIoT)和机器学习技术的发展&…...
设计模式-观察着模式
观察者模式 观察者模式 (Observer Pattern) 是一种行为型设计模式,它定义了对象之间一种一对多的依赖关系,当一个对象(称为主题或可观察者)的状态发生改变时,所有依赖于它的对象(称为观察者)都…...

《架构即未来》笔记
思维导图 第一部分:可扩展性组织的人员配置 第二部分:构建可扩展的过程 第三部分:可扩展的架构方案 第四部分:其他的问题和挑战 资料 问软件工程研究所: https://www.sei.cmu.edu/ AKF公司博客: http://www.akfpart…...
stm32—ADC和DAC
ADC和DAC 在嵌入式系统中,微控制器经常需要与现实世界的模拟信号进行交互。STM32微控制器内置了模拟数字转换器(ADC)和数字模拟转换器(DAC),它们是实现这种交互的关键模块。 1. 模拟数字转换器(…...

ubuntu2404 gpu 没接显示器,如何保证远程显示的分辨率
1. 使用 xserver-xorg-video-dummy 创建虚拟显示器 如果系统在无物理显示器连接时无法识别显示输出,可以使用 xserver-xorg-video-dummy 驱动程序创建虚拟显示器。以下是设置步骤: 安装虚拟显示器驱动程序: sudo apt install xserver-xorg-v…...

【基于阿里云搭建数据仓库(离线)】使用UDTF时出现报错“FlatEventUDTF cannot be resolved”
目录 问题: 可能的原因有: 解决方法: 问题: 已经将包含第三方依赖的jar包上传到dataworks,并且成功注册函数,但是还是报错:“FlatEventUDTF cannot be resolved”,如下:…...

Pycharm的终端无法使用Anaconda命令行问题详细解决教程
很多初学者在Windows系统上安装了Anaconda后,在PyCharm终端中运行Conda命令时,会遇到以下错误: conda : 无法将“conda”项识别为 cmdlet、函数、脚本文件或可运行程序的名称。 请检查名称的拼写,如果包括路径,请确保…...

SAP学习笔记 - 开发24 - 前端Fiori开发 Filtering(过滤器),Sorting and Grouping(排序和分组)
上一章讲了SAP Fiori开发的表达式绑定,自定义格式化等内容。 SAP学习笔记 - 开发23 - 前端Fiori开发 Expression Binding(表达式绑定),Custom Formatters(自定义格式化)-CSDN博客 本章继续讲SAP Fiori开发…...
【Flask】:轻量级Python Web框架详解
什么是Flask? Flask是一个用Python编写的轻量级Web应用框架。它被称为"微框架"(microframework),因为它核心简单但可扩展性强,不强制使用特定的项目结构或库。Flask由Armin Ronacher开发,基于Werkzeug WSGI工具包和Jin…...

自建 dnslog 回显平台:渗透测试场景下的隐蔽回显利器
🔍 背景介绍 在渗透测试与红队评估过程中,DNS 外带(DNS Exfiltration) 是一种常见且隐蔽的通信通道。由于多数目标环境默认具备外网 DNS 解析能力,即便在 无回显、无文件上传权限 的条件下,仍可通过 DNS 请…...

Digital IC Design Flow
Flow介绍 1.设计规格 架构师根据市场需求制作算法模型(Algorithm emulation)及芯片架构(Chip architecture),确定芯片设计规格书(Chip design specification) 原型验证 原型验证(Prototype Validation)通常位于产品开发流程的前期阶段,主要是在设计和开发的初步阶…...

设备健康管理的范式革命:中讯烛龙全链路智能守护系统
当工业设备的“亚健康”状态导致隐性产能损失高达23%时,中讯烛龙推出 “感知-诊断-决策-闭环”四位一体解决方案,让设备全生命周期健康管理成为企业增长的隐形引擎。 一、行业痛点:传统运维的三大断层 1. 健康感知盲区 某风电场因无法捕…...

循环神经网络(RNN):从理论到翻译
循环神经网络(RNN)是一种专为处理序列数据设计的神经网络,如时间序列、自然语言或语音。与传统的全连接神经网络不同,RNN具有"记忆"功能,通过循环传递信息,使其特别适合需要考虑上下文或顺序的任…...

Redis:常用数据结构 单线程模型
🌈 个人主页:Zfox_ 🔥 系列专栏:Redis 🔥 常用数据结构 🐳 Redis 当中常用的数据结构如下所示: Redis 在底层实现上述数据结构的过程中,会在源码的角度上对于上述的内容进行特定的…...

夏普比率(Sharpe ratio)
具有投资常识的人都明白,投资光看收益是不够的,还要看承受的风险,也就是收益风险比。 夏普比率描述的正是这个概念,即每承受一单位的总风险,会产生多少超额的报酬。 用数学公式描述就是: 其中࿱…...

【优选算法】模拟 问题算法
一:替换所有的问号 class Solution { public:string modifyString(string s) {int n s.size();for(int i 0; i < n; i){if(s[i] ?){for(char ch a; ch < z; ch){if((i0 && ch !s[i1]) || (in-1 && ch ! s[i-1]) || ( i>0 &&…...

Flask+LayUI开发手记(八):通用封面缩略图上传实现
前一节做了头像上传的程序,应该说,这个程序编写和操作都相当繁琐,实际上,头像这种缩略图在很多功能中都会用到,屏幕界面有限,绝不会给那么大空间摆开那么大一个界面,更可能的处理,就…...

低代码采购系统搭建:鲸采云+能源行业订单管理自动化案例
在能源行业数字化转型浪潮下,某大型能源集团通过鲸采云低代码平台,仅用3周时间就完成了采购订单管理系统的定制化搭建。本文将揭秘这一成功案例的实施路径与关键成效。 项目背景与挑战 该企业面临: 供应商分散:200供应商使用不同…...

android关于pthread的使用过程
文章目录 简介代码流程pthread使用hello_test.cppAndroid.bp 编译过程报错处理验证过程 简介 android开发经常需要使用pthread来编写代码实现相关的业务需求 代码流程 pthread使用 需要查询某个linux函数的方法使用,可以使用man 函数名 // $ man pthread_crea…...
Faiss vs Milvus 深度对比:向量数据库技术选型指南
Faiss vs Milvus 深度对比:向量数据库技术选型指南 引言:向量数据库的时代抉择 在AI应用爆发的今天,企业和开发者面临着如何存储和检索海量向量数据的重大技术选择。作为当前最受关注的两大解决方案,Faiss和Milvus代表了两种不同…...
慢慢欣赏linux 之 last = switch_to(prev, next)分析
last switch_to(prev, next); 为什么需要定义last作为调用switch_to之前的prev的引用 原因如下: struct task_struct * switch_to(struct task_struct *prev,struct task_struct *next) {... ...return cpu_switch_to(prev, next);> .global cpu_switch_tocpu_…...

如何用 HTML 展示计算机代码
原文:如何用 HTML 展示计算机代码 | w3cschool笔记 (请勿将文章标记为付费!!!!) 在编程学习和文档编写过程中,清晰地展示代码是一项关键技能。HTML 作为网页开发的基础语言&#x…...

2025年ESWA SCI1区TOP,自适应学习粒子群算法AEPSO+动态周期调节灰色模型,深度解析+性能实测
目录 1.摘要2.粒子群算法PSO原理3.改进策略4.结果展示5.参考文献6.代码获取7.算法辅导应用定制读者交流 1.摘要 能源数据的科学预测对于能源行业决策和国家经济发展具有重要意义,尤其是短期能源预测,其精度直接影响经济运行效率。为了更好地提高预测模型…...

LeetCode - 53. 最大子数组和
目录 题目 Kadane 算法核心思想 Kadane 算法的步骤分析 读者可能的错误写法 正确的写法 题目 53. 最大子数组和 - 力扣(LeetCode) Kadane 算法核心思想 定义状态变量: currentSum: 表示以当前元素为结束的子数组的最大和。 maxSum: 记录全局最大…...
稻米分类和病害检测数据集(猫脸码客第237期)
稻米分类图像数据集:驱动农业智能化发展的核心资源 引言 在全球农业体系中,稻米作为最关键的粮食作物之一,其品种多样性为人类饮食提供了丰富选择。然而,传统稻米分类方法高度依赖人工经验,存在效率低、主观性强等缺…...
DOM(文档对象模型)深度解析
DOM(文档对象模型)深度解析 DOM 是 HTML/XML 文档的树形结构表示,提供了一套让 JavaScript 动态操作网页内容、结构和样式的接口。 一、DOM 核心概念 1. 节点(Node)类型 类型值说明示例ELEMENT_NODE1元素节点<div>, <p>TEXT_NODE3文本节点元素内的文字COMMEN…...
四、Sqoop 导入表数据子集
作者:IvanCodes 日期:2025年6月4日 专栏:Sqoop教程 当不需要将关系型数据库中的整个表一次性导入,而是只需要表中的一部分数据时,Sqoop 提供了多种方式来实现数据子集的导入。这通常通过过滤条件或选择特定列来完成。 …...

【读代码】从预训练到后训练:解锁语言模型推理潜能——Xiaomi MiMo项目深度解析
项目开源地址:https://github.com/XiaomiMiMo/MiMo 一、基本介绍 Xiaomi MiMo是小米公司开源的7B参数规模语言模型系列,专为复杂推理任务设计。项目包含基础模型(MiMo-7B-Base)、监督微调模型(MiMo-7B-SFT)和强化学习模型(MiMo-7B-RL)等多个版本。其核心创新在于通过…...

DROPP算法详解:专为时间序列和空间数据优化的PCA降维方案
DROPP (Dimensionality Reduction for Ordered Points via PCA) 是一种专门针对有序数据的降维方法。本文将详细介绍该算法的理论基础、实现步骤以及在降维任务中的具体应用。 在现代数据分析中,高维数据集普遍存在特征数量庞大的问题。这种高维特性不仅增加了计算…...