ESP32-IDF http请求崩溃问题分析与解决

文章目录

  • esp32s3 http请求崩溃
  • 问题代码讨论
  • 修正后不崩溃的代码
  • esp32相关文章

ESP32S3板子, 一运行http请求百度网站的例子, 就会panic死机, 记录下出现及解决过程.

esp32s3 http请求崩溃

一执行http请求的perform就会崩溃,
打印如图
在这里插入图片描述
ESP32-IDF 的http请求代码是根据官方demo来改的,
第一步先连接wifi,
连接上后执行http get请求百度网站.
理论上写法是没问题的,但是运行到板子上发现很容易崩溃.

问题代码讨论

会在可能有问题的地方注释,有4个问题点,具体看代码 ,
最主要问题是运行内存有限, 容易发生栈或堆溢出或越界导致崩溃.

#include <stdio.h>
#include <pthread.h>#include <string.h>
#include <stdlib.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_err.h"
#include "esp_log.h"
#include "esp_system.h"
#include "nvs_flash.h"
#include "esp_event.h"
#include "esp_netif.h"
#include "esp_wifi.h"
#include "esp_tls.h"
#include "esp_crt_bundle.h"
#include "esp_http_client.h"static const char *TAG = "HTTP_REQUEST";// 这里的buffer要适当, 如果改太大了, 比如10240就可能导致死机, 要根据实际运行结果做调整
#define MAX_HTTP_OUTPUT_BUFFER 2048
#define HTTP_URL "http://www.baidu.com"// HTTP 请求的处理函数
esp_err_t http_event_handler(esp_http_client_event_t *evt)
{// 缓存http响应的bufferstatic char *output_buffer;// 已经读取的字节数static int output_len;switch(evt->event_id) {case HTTP_EVENT_ERROR:ESP_LOGD(TAG, "HTTP_EVENT_ERROR");break;case HTTP_EVENT_ON_CONNECTED:ESP_LOGD(TAG, "HTTP_EVENT_ON_CONNECTED");break;case HTTP_EVENT_HEADER_SENT:ESP_LOGD(TAG, "HTTP_EVENT_HEADER_SENT");break;case HTTP_EVENT_ON_HEADER:ESP_LOGD(TAG, "HTTP_EVENT_ON_HEADER, key=%s, value=%s", evt->header_key, evt->header_value);break;case HTTP_EVENT_ON_DATA:ESP_LOGD(TAG, "HTTP_EVENT_ON_DATA, len=%d", evt->data_len);if (!esp_http_client_is_chunked_response(evt->client)) {if (evt->user_data) {// 问题1: 这里没有做防溢出限制, 当http返回的数据长度趤过预留的buffer大小MAX_HTTP_OUTPUT_BUFFER时就会溢出崩溃memcpy(evt->user_data + output_len, evt->data, evt->data_len);} else {if (output_buffer == NULL) {// 问题2: 这里直接用malloc申请http返回的数据长度的堆空间, 实测在esp32s3板子上跑会崩溃output_buffer = (char *) malloc(esp_http_client_get_content_length(evt->client));output_len = 0;if (output_buffer == NULL) {ESP_LOGE(TAG, "Failed to allocate memory for output buffer");return ESP_FAIL;}}memcpy(output_buffer + output_len, evt->data, evt->data_len);}output_len += evt->data_len;}break;case HTTP_EVENT_ON_FINISH:ESP_LOGD(TAG, "HTTP_EVENT_ON_FINISH");if (output_buffer != NULL) {// Response is accumulated in output_buffer. Uncomment the below line to print the accumulated response// ESP_LOG_BUFFER_HEX(TAG, output_buffer, output_len);free(output_buffer);output_buffer = NULL;}output_len = 0;break;case HTTP_EVENT_DISCONNECTED:ESP_LOGI(TAG, "HTTP_EVENT_DISCONNECTED");if (output_buffer != NULL) {free(output_buffer);output_buffer = NULL;}output_len = 0;break;}return ESP_OK;
}void request(const char *url) {printf("request  -----------1\n");// 响应结果放在这里char local_response_buffer[MAX_HTTP_OUTPUT_BUFFER] = {0};// 创建一个 HTTP 客户端配置esp_http_client_config_t config = {.method = HTTP_METHOD_GET,.url = url,.event_handler = http_event_handler,.user_data = local_response_buffer,.disable_auto_redirect = true,};// 创建一个 HTTP 客户端并执行 GET 请求esp_http_client_handle_t client = esp_http_client_init(&config);printf("request  -----------2\n");esp_err_t err = esp_http_client_perform(client); // 请求百度网页时,一执行这行系统就会崩溃printf("request  -----------3\n");// 检查请求是否成功if (err == ESP_OK) {int len =  esp_http_client_get_content_length(client);ESP_LOGI(TAG, "Status = %d, content_length = %d",esp_http_client_get_status_code(client),//状态码len);//数据长度} else {printf("HTTP GET request failed: %s\n", esp_err_to_name(err));}printf("Response: %.*s\n", strlen(local_response_buffer), local_response_buffer);//断开并释放资源esp_http_client_cleanup(client);printf("request  -----------4\n");
}void http_test_task(void *arg)
{sleep(15);request(HTTP_URL);vTaskDelete(NULL);
}/*** @brief WiFi 的事件循环Handler* @param arg* @param event_base* @param event_id* @param event_data*/
void wifi_event_handler(void *arg, esp_event_base_t event_base, int32_t event_id, void *event_data)
{printf("wifi_event_handler base:%s, id:%d\n", event_base, event_id);if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_START){printf("esp_wifi_connect\n");esp_wifi_connect();}else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_DISCONNECTED){printf("esp_wifi_connect\n");esp_wifi_connect();}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("ESP32", "IP地址:: " IPSTR, IP2STR(&event->ip_info.ip));//request(HTTP_URL); 问题点3: 获取到ip地址后,不要直接在这里执行http请求, 否则会直接崩溃}
}void app_main(void)
{esp_err_t ret = nvs_flash_init(); // 初始化默认NVS分区if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND){ESP_ERROR_CHECK(nvs_flash_erase()); // 擦除默认NVS分区ret = nvs_flash_init();             // 初始化默认NVS分区}ESP_ERROR_CHECK(ret);ESP_ERROR_CHECK(esp_netif_init());                // 初始化底层TCP/IP堆栈ESP_ERROR_CHECK(esp_event_loop_create_default()); // 创建默认事件循环esp_netif_create_default_wifi_sta(); // 创建默认的WIFI STA。wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();esp_wifi_init(&cfg); // 初始化WiFi为WiFi驱动程序wifi_sta_config_t cfg_sta = {.ssid = "black",.password = "black1234",.threshold.authmode = WIFI_AUTH_WPA2_PSK,   //加密方式.pmf_cfg = {.capable = true,.required = false},};esp_wifi_set_config(WIFI_IF_STA, (wifi_config_t *)&cfg_sta); // 设置ESP32 STA或AP的配置esp_wifi_set_mode(WIFI_MODE_STA); // 设置WiFi操作模式// 将事件处理程序的实例注册到默认循环中           任何事件esp_event_handler_instance_register(WIFI_EVENT, ESP_EVENT_ANY_ID, wifi_event_handler, NULL, NULL);// 将事件处理程序的实例注册到默认循环中            工作站从连接的AP获得IP事件esp_event_handler_instance_register(IP_EVENT, IP_EVENT_STA_GOT_IP, wifi_event_handler, NULL, NULL);esp_wifi_start(); // 根据当前配置启动wifixTaskCreate(&http_test_task, "http_test_task", 8192, NULL, 5, NULL); //问题点4: 这里参数需要设置足够大的栈大小, 否则会导致崩溃
}

修正后不崩溃的代码

百度网页返回的http结果太多了,会导致空间不够,
针对问题代码, 做出调整, 对栈空间大小做限制, 当http返回内容过长时,直接丢弃

#include <stdio.h>
#include <pthread.h>#include <string.h>
#include <stdlib.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_err.h"
#include "esp_log.h"
#include "esp_system.h"
#include "nvs_flash.h"
#include "esp_event.h"
#include "esp_netif.h"
#include "esp_wifi.h"
#include "esp_tls.h"
#include "esp_crt_bundle.h"
#include "esp_http_client.h"static const char *TAG = "HTTP_REQUEST";
#define MAX_HTTP_OUTPUT_BUFFER 2048
#define HTTP_URL "http://www.baidu.com"// HTTP 请求的处理函数
esp_err_t http_event_handler(esp_http_client_event_t *evt)
{// 缓存http响应的bufferstatic char *output_buffer;// 已经读取的字节数static int output_len;switch(evt->event_id) {case HTTP_EVENT_ERROR:ESP_LOGD(TAG, "HTTP_EVENT_ERROR");break;case HTTP_EVENT_ON_CONNECTED:ESP_LOGD(TAG, "HTTP_EVENT_ON_CONNECTED");break;case HTTP_EVENT_HEADER_SENT:ESP_LOGD(TAG, "HTTP_EVENT_HEADER_SENT");break;case HTTP_EVENT_ON_HEADER:ESP_LOGD(TAG, "HTTP_EVENT_ON_HEADER, key=%s, value=%s", evt->header_key, evt->header_value);break;case HTTP_EVENT_ON_DATA:ESP_LOGD(TAG, "HTTP_EVENT_ON_DATA, len=%d", evt->data_len);if (!esp_http_client_is_chunked_response(evt->client)) {if (evt->user_data) {// 这里对buffer长度进行判断, 如果http返回长度过长, 为防止溢出就丢弃,否则进行追加拷贝int left = MAX_HTTP_OUTPUT_BUFFER - output_len -1;if (left > evt->data_len)memcpy(evt->user_data + output_len, evt->data, evt->data_len);else if (left > 0)memcpy(evt->user_data + output_len, evt->data, left);elseESP_LOGI(TAG, "HTTP_EVENT_ON_DATA, buffer full");} else {// 如果实测user_data设置为空时,走这里申请堆内存会崩溃则可以注释掉这段,否则可以使用if (output_buffer == NULL) {output_buffer = (char *) malloc(esp_http_client_get_content_length(evt->client));output_len = 0;if (output_buffer == NULL) {ESP_LOGE(TAG, "Failed to allocate memory for output buffer");return ESP_FAIL;}}memcpy(output_buffer + output_len, evt->data, evt->data_len);}output_len += evt->data_len;}break;case HTTP_EVENT_ON_FINISH:ESP_LOGD(TAG, "HTTP_EVENT_ON_FINISH");if (output_buffer != NULL) {// Response is accumulated in output_buffer. Uncomment the below line to print the accumulated response// ESP_LOG_BUFFER_HEX(TAG, output_buffer, output_len);free(output_buffer);output_buffer = NULL;}output_len = 0;break;case HTTP_EVENT_DISCONNECTED:ESP_LOGI(TAG, "HTTP_EVENT_DISCONNECTED");if (output_buffer != NULL) {free(output_buffer);output_buffer = NULL;}output_len = 0;break;}return ESP_OK;
}void request(const char *url) {printf("request  -----------1\n");// 响应结果放在这里char local_response_buffer[MAX_HTTP_OUTPUT_BUFFER] = {0};// 创建一个 HTTP 客户端配置esp_http_client_config_t config = {.method = HTTP_METHOD_GET,.url = url,.event_handler = http_event_handler,.user_data = local_response_buffer,.disable_auto_redirect = true,};// 创建一个 HTTP 客户端并执行 GET 请求esp_http_client_handle_t client = esp_http_client_init(&config);printf("request  -----------2\n");esp_err_t err = esp_http_client_perform(client); // 请求百度网页时,一执行这行系统就会崩溃printf("request  -----------3\n");// 检查请求是否成功if (err == ESP_OK) {int len =  esp_http_client_get_content_length(client);ESP_LOGI(TAG, "Status = %d, content_length = %d",esp_http_client_get_status_code(client),//状态码len);//数据长度} else {printf("HTTP GET request failed: %s\n", esp_err_to_name(err));}printf("Response: %.*s\n", strlen(local_response_buffer), local_response_buffer);//断开并释放资源esp_http_client_cleanup(client);printf("request  -----------4\n");
}void http_test_task(void *arg)
{sleep(15);request(HTTP_URL);vTaskDelete(NULL);
}/*** @brief WiFi 的事件循环Handler* @param arg* @param event_base* @param event_id* @param event_data*/
void wifi_event_handler(void *arg, esp_event_base_t event_base, int32_t event_id, void *event_data)
{printf("wifi_event_handler base:%s, id:%d\n", event_base, event_id);if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_START){printf("esp_wifi_connect\n");esp_wifi_connect();}else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_DISCONNECTED){printf("esp_wifi_connect\n");esp_wifi_connect();}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("ESP32", "IP地址:: " IPSTR, IP2STR(&event->ip_info.ip));//request(HTTP_URL); 问题点2: 获取到ip地址后,不要直接在这里执行http请求, 否则会直接崩溃 , 这里注释掉不用}
}void app_main(void)
{esp_err_t ret = nvs_flash_init(); // 初始化默认NVS分区if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND){ESP_ERROR_CHECK(nvs_flash_erase()); // 擦除默认NVS分区ret = nvs_flash_init();             // 初始化默认NVS分区}ESP_ERROR_CHECK(ret);ESP_ERROR_CHECK(esp_netif_init());                // 初始化底层TCP/IP堆栈ESP_ERROR_CHECK(esp_event_loop_create_default()); // 创建默认事件循环esp_netif_create_default_wifi_sta(); // 创建默认的WIFI STA。wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();esp_wifi_init(&cfg); // 初始化WiFi为WiFi驱动程序wifi_sta_config_t cfg_sta = {.ssid = "black",.password = "black1234",.threshold.authmode = WIFI_AUTH_WPA2_PSK,   //加密方式.pmf_cfg = {.capable = true,.required = false},};esp_wifi_set_config(WIFI_IF_STA, (wifi_config_t *)&cfg_sta); // 设置ESP32 STA或AP的配置esp_wifi_set_mode(WIFI_MODE_STA); // 设置WiFi操作模式// 将事件处理程序的实例注册到默认循环中           任何事件esp_event_handler_instance_register(WIFI_EVENT, ESP_EVENT_ANY_ID, wifi_event_handler, NULL, NULL);// 将事件处理程序的实例注册到默认循环中            工作站从连接的AP获得IP事件esp_event_handler_instance_register(IP_EVENT, IP_EVENT_STA_GOT_IP, wifi_event_handler, NULL, NULL);esp_wifi_start(); // 根据当前配置启动wifixTaskCreate(&http_test_task, "http_test_task", 8192, NULL, 5, NULL); //问题点3: 这里参数需要设置足够大的栈大小, 否则会导致崩溃, 可以根据实测来改, 最好MAX_HTTP_OUTPUT_BUFFER大,否则可能会崩溃.
}

这样连上wifi后, http get请求百度网页就正常了, 可以打印部分内容, 建议换成简单的页面的网址, 百度返回的数据太多了.

esp32相关文章

可见我的esp32专栏
作者:帅得不敢出门 csdn原创谢绝转载

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

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

相关文章

Qt:玩转QPainter序列六(图形)

前言 继续看源码。 正文 剩下的大部分都是画各种图形的函数&#xff0c;它们一般都有多个重载版本&#xff0c;我就不一 一介绍使用了&#xff0c;只挑其中的一部分使用一下。 在 QPainter 类中&#xff0c;这些方法涉及到绘图的各种功能&#xff0c;主要用于设置视图变换、…

kube-scheduler调度任务的执行过程分析与源码解读(二)

概述 摘要&#xff1a; 上文我们对Kube-scheduler的启动流程进行了分析&#xff0c;本文继续探究kube-scheduler执行pod的调度任务的过程。 正文 说明&#xff1a;基于 kubernetes v1.12.0 源码分析 上文讲到kube-scheduler组件通过sched.Run() 启动调度器实例。在sched.Run(…

校园牛奶订购配送小程序开发制作方案

校园牛奶订购配送小程序系统的开发方案&#xff0c;包括对用户需求的分析、目标用户的界定、使用场景的设定以及开发功能模块的规划。校园牛奶订购配送小程序系统主要是为校园内学生和教职工提供牛奶订购与配送服务。 目标用户 主要面向在校学生、教职工以及其他有牛奶订购需求…

这四种人不能合作做生意

合伙创业千万不要和这四种人合伙&#xff0c;不然公司做大了都不是你的&#xff01; 一、不愿出钱的人&#xff0c;不愿出钱就不会有决心。公司一旦有风吹草动&#xff0c;最先跑路的都是没有出钱的。 二、不愿付出时间的人&#xff0c;想用业余时间参与&#xff0c;不愿全身心…

如何使用Svg矢量图封装引用到vue3项目中

前言 在现代前端开发中&#xff0c;SVG&#xff08;可缩放矢量图形&#xff09;因其高质量和灵活性成为了图标和图形设计的热门选择。对于 Vue 3 项目而言&#xff0c;将 SVG 图标封装和引用到项目中不仅能提升性能&#xff0c;还能带来更高的可维护性和一致性。SVG 图标本质上…

卡西莫多的诗文集2022-2024.8月定稿

通过网盘分享的文件&#xff1a;卡西莫多的诗文集2022-2024.8月30-A5.pdf 链接: https://pan.baidu.com/s/1_BrcKvUthFLlty8dWNZxjQ?pwdutwd 提取码: utwd 自从解锁了一项新技能后&#xff0c;从藏内容诗开始&#xff0c;自己积攒到现在不知不觉也积累了一些诗&#xff0c;看…

Runway删库跑路,真的run away了!

没有任何通知&#xff0c;Runway在Hugging Face上的内容全部删除了&#xff01; 目前具体原因不明。Runway的主页只留下了一句话&#xff1a; 我们不再对HuggingFace账号进行维护。 据悉&#xff0c;Runway在Hugging Face上&#xff0c;最火的、也是争议最大的项目&#xff0c;…

【spring】学习笔记1:starter和application

https://spring.io/toolsSpring Boot Extension Pack vs版本 使用Spring Tool Suite初始化Spring项目

Python__面向对象__多态学习

目录 一、多态 1.多态定义理解 2.实例属性和类属性 3.类相关的函数 (1) 实例方法 (2)类方法 (3)静态方法 一、多态 1.多态定义理解 在Python中&#xff0c;多态是一种特性&#xff0c;类似于一个接口&#xff0c;允许在一个对象中的一个操作可作用在不同类型的对象上…

IT管理员的秘密武器:高效管理服务器的远程控制软件

如果你出外勤却紧急需要一份文件&#xff0c;是不是有种热锅上蚂蚁的感觉。这时候如果能远程公司的电脑就能获得马上获得那份心心念念的文件咯。今天我就分享几款轻松好操作的远程控制工具帮你走出困境。 1.向日葵远程控制 链接直通车&#xff1a;https://down.oray.com 这个…

进程间通信----管道篇

目录 一丶 无名管道 1. 特点 2. 读写特性 3. 函数接口 二丶有名管道 1.特点&#xff1a; 2.函数接口 3. 读写特性 一丶 无名管道 1. 特点 1. 只能用于具有亲缘关系的进程之间的通信 2. 半双工的通信模式&#xff0c;具有固定的读端和写端 3. 管道可以…

4G手机智能遥控开关

什么是4G手机智能遥控开关 4G手机智能遥控开关作为现代智能家居与工业自动化的重要组成部分&#xff0c;提供了便捷、高效的远程控制方案。它利用4G通信技术&#xff0c;允许用户随时随地通过智能手机或其他移动设备控制电器设备的开关状态&#xff0c;适用于家庭、办公、工业等…

【Android】MotionLayout实现动画效果

【Android】MotionLayout实现开场动画 在移动应用开发中&#xff0c;动画不仅仅是美化界面的工具&#xff0c;它更是提升用户体验的关键手段。Android 平台一直以来都提供了丰富的动画框架&#xff0c;但随着应用复杂性的增加&#xff0c;开发者对动画的需求也变得更加复杂和多…

AcWing898. 数字三角形

线性DP 董晓老师的讲解是从下标0开始算的&#xff0c;其实我们从1开始也可以&#xff0c;我感觉这里从1开始更好理解。是从下往上计算的。j负责列的计算&#xff0c;往上计算时逐步收窄横向的范围&#xff0c;i是纵向的从下往上算&#xff0c; 下面是内存布局 下面是逻辑上的…

android 离线的方式使用下载到本地的gradle

1、android studio在下载gradle的时候&#xff0c;特别慢&#xff0c;有的时候会下载不完的情况&#xff0c;这样我们就要离线使用了。 2、下载Gradle Gradle | Releases 或者 Releases gradle/gradle GitHub Gradle | Releases 这里我们下载8.10 complete版本&#xff0c…

Tomcat10安装

Tomcat下载 进入官网下载https://tomcat.apache.org 注意tomcat版本和Java版本的对应关系&#xff1a; 配置好JAVA_HOME 安装tomcat前&#xff0c;需要先配置好JAVA_HOME&#xff0c;因为tomcat启动时候默认会找环境里面的JAVA_HOME&#xff0c;这里选择的Java版本是java1…

【工具篇】高效记忆方法之AnKi工具

&#x1f60a;你好&#xff0c;我是南极。正在变强的路上不断地努力着&#x1f4aa; &#x1f514;今天和大家分享一些记忆的方法&#xff0c;以及推荐了一款用于复习和巩固知识的软件AnKi。 对我们程序员而言&#xff0c;平常学习的东西会比较多&#xff0c;有时呢学的东西会…

结合代码详细讲解DDPM的训练和采样过程

本篇文章结合代码讲解Denoising Diffusion Probabilistic Models&#xff08;DDPM&#xff09;&#xff0c;首先我们先不关注推导过程&#xff0c;而是结合代码来看一下训练和推理过程是如何实现的&#xff0c;推导过程会在别的文章中讲解&#xff1b;首先我们来看一下论文中的…

<C++> AVLTree

目录 1. AVL概念 2. AVL树节点的定义 3. AVL树的插入 4. AVL树的旋转 5. AVL树的验证 6. AVL树的删除 7. AVL树的性能 暴力搜索、二分搜索、二叉搜索树、二叉平衡搜索树&#xff08;AVL、红黑树&#xff09;、多叉平衡搜索树&#xff08;B树&#xff09;、哈希表 1. AVL概念 二…

【C++ Primer Plus习题】7.2

问题: 解答: #include <iostream> using namespace std;#define MAX 10int input(float* grade, int len) {int i 0;for (i 0; i < len; i){cout << "请输入第" << i 1 << "个高尔夫成绩(按0结束):";cin >> grade[i]…