ESP32之wifi_HTTP

发布于:2025-08-12 ⋅ 阅读:(14) ⋅ 点赞:(0)

前言
国产的芯片的,性价比 真是高,ESP32-3C 经典版 12.9 SRAM 400K flash 4M ,主频160MHZ,
这跟STM32 比,吓死人, 自带蓝牙与WIFI,连模块钱省了,不过,
看下各自占用的资源对比吧 需要联网 不是太苛刻的环境下,首选择ESP32,还有GD32(主频高点),这个也是基于ARM,对比STM32 也不便宜,国产替补品,STM32好多也是国产芯片
STM32 智能小车 RAM 20K flash 64k ARM指令 8-10元
在这里插入图片描述
ESP32 -3C HTTP client RAM 400k flash 4M 基于RISC-V指令 11-13元
在这里插入图片描述

1:环境
ESP32 3C 经典版 TYPEC 可以下载也可以当UART0 使用 (GPIO 8,9)
VSCODE+IDF5.4.1 安装可能需要科学上网
在这里插入图片描述

2:直接上代码
main.c

#include <stdio.h>
#include <string.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_system.h"
#include "esp_wifi.h"
#include "esp_event.h"
#include "esp_log.h"
#include "nvs_flash.h"
#include "esp_http_client.h"
#include "esp_netif.h"  // 替代 tcpip_adapter 的新网络接口组件

// WiFi 配置(替换为实际的 WiFi 名称和密码)
#define WIFI_SSID "自己的SSID"
#define WIFI_PASSWORD "自己的密码"

// 日志标签
static const char *TAG = "WIFI_HTTP_EXAMPLE";
#define REQUEST_URL "http://192.168.1.3:8080/hello"

// 事件组:用于等待 WiFi 连接成功
static EventGroupHandle_t s_wifi_event_group;
const int WIFI_CONNECTED_BIT = BIT0;


// 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) {
        // WiFi 启动后开始连接
        esp_wifi_connect();
    } else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_DISCONNECTED) {
        // 连接断开后重试
        esp_wifi_connect();
        xEventGroupClearBits(s_wifi_event_group, WIFI_CONNECTED_BIT);
        ESP_LOGW(TAG, "WiFi disconnect,try again...");
    } else if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP) {
        // 获取 IP 地址后标记连接成功
        ip_event_got_ip_t* event = (ip_event_got_ip_t*) event_data;
        ESP_LOGI(TAG, "get IP address: " IPSTR, IP2STR(&event->ip_info.ip));
        xEventGroupSetBits(s_wifi_event_group, WIFI_CONNECTED_BIT);
    }
}

// 初始化 WiFi 为 Station 模式
void wifi_init_sta(void)
{
    // 1. 初始化事件组(用于同步 WiFi 连接状态)
    s_wifi_event_group = xEventGroupCreate();

    // 2. 初始化 esp-netif(替代旧的 tcpip_adapter_init())
    ESP_ERROR_CHECK(esp_netif_init());

    // 3. 创建默认事件循环(处理 WiFi 和 IP 事件)
    ESP_ERROR_CHECK(esp_event_loop_create_default());

    // 4. 创建默认的 WiFi Station 网络接口
    esp_netif_create_default_wifi_sta();

    // 5. 初始化 WiFi 驱动
    wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
    ESP_ERROR_CHECK(esp_wifi_init(&cfg));

    // 6. 注册事件处理函数(监听 WiFi 和 IP 事件)
    ESP_ERROR_CHECK(esp_event_handler_register(WIFI_EVENT, ESP_EVENT_ANY_ID, &event_handler, NULL));
    ESP_ERROR_CHECK(esp_event_handler_register(IP_EVENT, IP_EVENT_STA_GOT_IP, &event_handler, NULL));

    // 7. 配置 WiFi 连接参数(SSID 和密码)
    wifi_config_t wifi_config = {
        .sta = {
            .ssid = WIFI_SSID,
            .password = WIFI_PASSWORD,
        },
    };
    ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA));         // 设置为 Station 模式
    ESP_ERROR_CHECK(esp_wifi_set_config(ESP_IF_WIFI_STA, &wifi_config));  // 应用配置
    ESP_ERROR_CHECK(esp_wifi_start());                         // 启动 WiFi

    ESP_LOGI(TAG, "WiFi init finish,connect %s...", WIFI_SSID);
}

// HTTP 事件回调函数(处理服务器响应数据)
// 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)) {
                // 如果配置了user_data buffer,则把响应复制到该buffer中
                if (evt->user_data) {
                    memcpy(evt->user_data + output_len, evt->data, evt->data_len);
                } else {
                    // 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);
                    ESP_LOGD(TAG,"%.*s", evt->data_len, (char*)evt->data);
                }
                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;
        default:
        ESP_LOGI(TAG, "HTTP_EVENT_OTHER");
    }
    return ESP_OK;
}


char *str_to_hex_str(const char *input,int inputlen,char* output) {
    if (input == NULL) return NULL;
    size_t len = inputlen;//strlen(input);
    // 每个字符转十六进制占 2 个字符,再加上可能的分隔符、字符串结束符 '\0'
    // 这里示例没加分隔符,直接连续存,所以总长度是 len * 2 + 1
  //  char *hex_buf = (char *)malloc(len * 2 + 1);
 //   if (hex_buf == NULL) return NULL;

    char *p = output;//hex_buf;
    for (size_t i = 0; i < len; i++) {
        // 逐个字符格式化到 hex_buf
        p += sprintf(p, "%02x", (unsigned char)input[i]);
    }
    return output;
}

// 发送 HTTP GET 请求
void http_get_request(const char *url)
{
        // 响应结果放在这里
    char local_response_buffer[2048] = {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 请求
    // 创建一个 HTTP 客户端并执行 GET 请求
    esp_http_client_handle_t client = esp_http_client_init(&config);
    esp_err_t err = esp_http_client_perform(client);
    // 检查请求是否成功
    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);//数据长度
        if(len>0){
            local_response_buffer[len]=0;
            ESP_LOGI(TAG, "recv[%s]\n",local_response_buffer);
            // for(int i=0;i<len;i++){
            //    // ESP_LOGI(TAG, "recv server respon[%x]", sztemphex[i]);
            //    ESP_LOGI(TAG,"%02x",(unsigned char)(local_response_buffer[i]));
            // }
         //   char sztemphex[2048]={0,};
        //    memset(sztemphex,0,sizeof(sztemphex));
         //  str_to_hex_str(local_response_buffer,len,sztemphex);
        //    ESP_LOGI(TAG, "recv server respon[%s]", sztemphex);
        }
        
         
    } 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_LOGI(TAG, "recv server respon[%d]:%s",strlen(local_response_buffer), local_response_buffer);
    //断开并释放资源
    esp_http_client_cleanup(client);

}

void http_get_request_bak(const char *url)
{
    // 配置 HTTP 客户端
    // esp_http_client_config_t config = {
    //     .url = url,                  // 目标网址
    //     .event_handler = _http_event_handler,  // 响应处理回调
    //     .timeout_ms = 10000,         // 超时时间(10秒)
    // };
    esp_http_client_config_t config = {
    .url = REQUEST_URL,
    .event_handler = _http_event_handler,
    .timeout_ms = 10000,
    // 关键:显式指定 HTTP 版本为 1.1(避免自动降级)
   .transport_type = HTTP_TRANSPORT_OVER_TCP,
};

    // 初始化客户端并发送请求
    esp_http_client_handle_t client = esp_http_client_init(&config);
    esp_http_client_set_header(client, "User-Agent", "ESP32-HTTP-Example/1.0");
    esp_err_t err = esp_http_client_perform(client);

    if (err == ESP_OK) {
        ESP_LOGI(TAG, "HTTP state code: %d", esp_http_client_get_status_code(client));
        // 读取并打印响应内容
        //char response_buf[1024] = {0}; // 缓冲区,根据实际响应大小调整
       // int read_len = esp_http_client_read(client, response_buf, sizeof(response_buf) - 1);
         int total_len = 0;
         char buffer[1024] = {0};
         while (1) {
            int read_len = esp_http_client_read(client, buffer + total_len, sizeof(buffer) - total_len - 1);
            if (read_len <= 0) break; // 读取完毕或出错
            total_len += read_len;
            // 防止缓冲区溢出(可选,根据需求调整)
            if (total_len >= sizeof(buffer) - 1) break; 
        }
        buffer[total_len] = '\0'; // 确保字符串结尾
        ESP_LOGI(TAG, "recv server respon[%d]:%s",total_len,buffer);
        
        // if (read_len > 0) {
        //     ESP_LOGI(TAG, "recv server respon:%s",response_buf);
        //    // printf("%s\n", response_buf); // 直接打印原始响应
        // } else if (read_len == 0) {
        //     ESP_LOGI(TAG, "server respon NULL");
        // } else {
        //     ESP_LOGE(TAG, "server respon fail");
        // }
    } else {
        ESP_LOGE(TAG, "HTTP request fail: %s", esp_err_to_name(err));
    }

    // 清理资源
    esp_http_client_cleanup(client);
}

void app_main(void)
{
    // 1. 初始化 NVS(存储 WiFi 配置等信息)
    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());  // 若 NVS 满或版本不兼容,先擦除
        ret = nvs_flash_init();
    }
    ESP_ERROR_CHECK(ret);

    // 2. 初始化 WiFi 并连接
    wifi_init_sta();

    // 3. 等待 WiFi 连接成功(阻塞直到获取 IP)
    xEventGroupWaitBits(s_wifi_event_group, WIFI_CONNECTED_BIT,
                        pdFALSE, pdTRUE, portMAX_DELAY);
    ESP_LOGI(TAG, "WiFi connect success,start send HTTP request...");

    // 4. 访问目标网址(http://www.ip.cn/ 会重定向到 https://myip.xyz/zh/)
   // const char *url = "http://www.ip.cn/";
    ESP_LOGI(TAG, "vist url: %s", REQUEST_URL);
    http_get_request(REQUEST_URL);

    // 5. 程序保持运行(可添加循环请求逻辑)
    while (1) {
        vTaskDelay(pdMS_TO_TICKS(8000));  // 每 8 秒循环一次
        http_get_request(REQUEST_URL);  // 取消注释可实现定时重复请求
    }
}

golang server代码

package main

import (
	"context" // 添加缺失的context包
	"fmt"
	"log"
	"net/http"
	"os"
	"os/signal"
	"syscall"
	"time"
)

func main() {
	// 创建一个带有超时设置的服务器实例
	server := &http.Server{
		Addr:         ":8080",
		Handler:      setupRouter(),
		ReadTimeout:  10 * time.Second,
		WriteTimeout: 10 * time.Second,
		IdleTimeout:  30 * time.Second,
	}

	// 启动服务器的goroutine
	go func() {
		log.Printf("服务器启动,监听端口: %s\n", server.Addr)
		if err := server.ListenAndServe(); err != nil && err != http.ErrServerClosed {
			log.Fatalf("服务器启动失败: %v\n", err)
		}
	}()

	// 优雅关闭服务器
	waitForShutdown(server)
}

// 设置路由和中间件

func setupRouter() http.Handler {
	mux := http.NewServeMux()

	// 注册路由
	mux.HandleFunc("/", homeHandler)
	mux.HandleFunc("/hello", helloHandler)

	// 使用中间件包装路由
	return loggingMiddleware(mux)
}

// 首页处理器

func homeHandler(w http.ResponseWriter, r *http.Request) {
	w.Write([]byte("欢迎来到Go HTTP服务器!\n"))
}

// 问候处理器

func helloHandler(w http.ResponseWriter, r *http.Request) {
	curtime := time.Now().Unix()
	log.Printf("Received request from %s, Method: %s, Headers: %v",
		r.RemoteAddr, r.Method, r.Header)
	rep := fmt.Sprintf("hello_time=%v", curtime)
	w.Write([]byte(rep))
	//w.Write([]byte("hello,world!\n"))
	log.Println(fmt.Sprintf("recv request from %v time=%v len(rep)=%v_%v", r.RemoteAddr, curtime, len(rep), rep))
}

// 等待关闭信号并优雅地关闭服务器

func waitForShutdown(server *http.Server) {
	interruptChan := make(chan os.Signal, 1)
	signal.Notify(interruptChan, os.Interrupt, syscall.SIGINT, syscall.SIGTERM)

	// 等待中断信号
	<-interruptChan
	log.Println("接收到关闭信号,开始优雅关闭服务器...")

	// 创建一个5秒的超时时间来关闭服务器
	ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
	defer cancel()

	// 优雅关闭服务器,等待现有请求完成
	if err := server.Shutdown(ctx); err != nil {
		log.Printf("服务器关闭错误: %v\n", err)
	} else {
		log.Println("服务器已优雅关闭")
	}
}


3:测试结果 如果对你又帮助,麻烦点个赞,加个关注
在这里插入图片描述


网站公告

今日签到

点亮在社区的每一天
去签到