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响应的buffer
- static 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(); // 根据当前配置启动wifi
- xTaskCreate(&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响应的buffer
- static 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);
- else
- ESP_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(); // 根据当前配置启动wifi
- xTaskCreate(&http_test_task, "http_test_task", 8192, NULL, 5, NULL); //问题点3: 这里参数需要设置足够大的栈大小, 否则会导致崩溃, 可以根据实测来改, 最好MAX_HTTP_OUTPUT_BUFFER大,否则可能会崩溃.
- }
复制代码 这样连上wifi后, http get哀求百度网页就正常了, 可以打印部门内容, 发起换成简单的页面的网址, 百度返回的数据太多了.
esp32相关文章
可见我的esp32专栏
作者:帅得不敢出门 csdn原创谢绝转载
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |