欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 新闻 > 社会 > ESP32S3 WIFI 实现TCP服务器和静态IP

ESP32S3 WIFI 实现TCP服务器和静态IP

2025/3/31 13:23:50 来源:https://blog.csdn.net/weixin_41613969/article/details/146527283  浏览:    关键词:ESP32S3 WIFI 实现TCP服务器和静态IP

一、 TCP服务器代码

代码由station_example_main的官方例程修改

/* WiFi station ExampleThis example code is in the Public Domain (or CC0 licensed, at your option.)Unless required by applicable law or agreed to in writing, thissoftware is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES ORCONDITIONS OF ANY KIND, either express or implied.
*/
#include <string.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/event_groups.h"
#include "esp_system.h"
#include "esp_wifi.h"
#include "esp_event.h"
#include "esp_log.h"
#include "nvs_flash.h"
#include <stdlib.h>
#include "lwip/err.h"
#include "lwip/sys.h"
#include "lwip/sockets.h"
#include <lwip/netdb.h>/* The examples use WiFi configuration that you can set via project configuration menuIf you'd rather not, just change the below entries to strings withthe config you want - ie #define EXAMPLE_WIFI_SSID "mywifissid"
*/
#define EXAMPLE_ESP_WIFI_SSID      CONFIG_ESP_WIFI_SSID
#define EXAMPLE_ESP_WIFI_PASS      CONFIG_ESP_WIFI_PASSWORD
#define EXAMPLE_ESP_MAXIMUM_RETRY  CONFIG_ESP_MAXIMUM_RETRY#define EXAMPLE_MAX_STA_CONN        4  // 最大客户端连接数
#define PORT                        8080
#define KEEPALIVE_IDLE              5
#define KEEPALIVE_INTERVAL          5
#define KEEPALIVE_COUNT             3#if CONFIG_ESP_WPA3_SAE_PWE_HUNT_AND_PECK
#define ESP_WIFI_SAE_MODE WPA3_SAE_PWE_HUNT_AND_PECK
#define EXAMPLE_H2E_IDENTIFIER ""
#elif CONFIG_ESP_WPA3_SAE_PWE_HASH_TO_ELEMENT
#define ESP_WIFI_SAE_MODE WPA3_SAE_PWE_HASH_TO_ELEMENT
#define EXAMPLE_H2E_IDENTIFIER CONFIG_ESP_WIFI_PW_ID
#elif CONFIG_ESP_WPA3_SAE_PWE_BOTH
#define ESP_WIFI_SAE_MODE WPA3_SAE_PWE_BOTH
#define EXAMPLE_H2E_IDENTIFIER CONFIG_ESP_WIFI_PW_ID
#endif
#if CONFIG_ESP_WIFI_AUTH_OPEN
#define ESP_WIFI_SCAN_AUTH_MODE_THRESHOLD WIFI_AUTH_OPEN
#elif CONFIG_ESP_WIFI_AUTH_WEP
#define ESP_WIFI_SCAN_AUTH_MODE_THRESHOLD WIFI_AUTH_WEP
#elif CONFIG_ESP_WIFI_AUTH_WPA_PSK
#define ESP_WIFI_SCAN_AUTH_MODE_THRESHOLD WIFI_AUTH_WPA_PSK
#elif CONFIG_ESP_WIFI_AUTH_WPA2_PSK
#define ESP_WIFI_SCAN_AUTH_MODE_THRESHOLD WIFI_AUTH_WPA2_PSK
#elif CONFIG_ESP_WIFI_AUTH_WPA_WPA2_PSK
#define ESP_WIFI_SCAN_AUTH_MODE_THRESHOLD WIFI_AUTH_WPA_WPA2_PSK
#elif CONFIG_ESP_WIFI_AUTH_WPA3_PSK
#define ESP_WIFI_SCAN_AUTH_MODE_THRESHOLD WIFI_AUTH_WPA3_PSK
#elif CONFIG_ESP_WIFI_AUTH_WPA2_WPA3_PSK
#define ESP_WIFI_SCAN_AUTH_MODE_THRESHOLD WIFI_AUTH_WPA2_WPA3_PSK
#elif CONFIG_ESP_WIFI_AUTH_WAPI_PSK
#define ESP_WIFI_SCAN_AUTH_MODE_THRESHOLD WIFI_AUTH_WAPI_PSK
#endif/* FreeRTOS event group to signal when we are connected*/
static EventGroupHandle_t s_wifi_event_group;/* The event group allows multiple bits for each event, but we only care about two events:* - we are connected to the AP with an IP* - we failed to connect after the maximum amount of retries */
#define WIFI_CONNECTED_BIT BIT0
#define WIFI_FAIL_BIT      BIT1
#define WIFI_CONNECTED_SUCCESS      BIT2// 客户端任务参数结构体
typedef struct {int socket;struct sockaddr_in addr;
} client_params_t;static const char *TAG = "wifi station";static int s_retry_num = 0;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 < EXAMPLE_ESP_MAXIMUM_RETRY) {esp_wifi_connect();s_retry_num++;ESP_LOGI(TAG, "retry to connect to the AP");} else {xEventGroupSetBits(s_wifi_event_group, WIFI_FAIL_BIT);}ESP_LOGI(TAG,"connect to the AP fail");} 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_SUCCESS |WIFI_CONNECTED_BIT);}
}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_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));wifi_config_t wifi_config = {.sta = {.ssid = EXAMPLE_ESP_WIFI_SSID,.password = EXAMPLE_ESP_WIFI_PASS,/* Authmode threshold resets to WPA2 as default if password matches WPA2 standards (password len => 8).* If you want to connect the device to deprecated WEP/WPA networks, Please set the threshold value* to WIFI_AUTH_WEP/WIFI_AUTH_WPA_PSK and set the password with length and format matching to* WIFI_AUTH_WEP/WIFI_AUTH_WPA_PSK standards.*/.threshold.authmode = ESP_WIFI_SCAN_AUTH_MODE_THRESHOLD,.sae_pwe_h2e = ESP_WIFI_SAE_MODE,.sae_h2e_identifier = EXAMPLE_H2E_IDENTIFIER,},};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_init_sta finished.");/* Waiting until either the connection is established (WIFI_CONNECTED_BIT) or connection failed for the maximum* number of re-tries (WIFI_FAIL_BIT). The bits are set by event_handler() (see above) */EventBits_t bits = xEventGroupWaitBits(s_wifi_event_group,WIFI_CONNECTED_BIT | WIFI_FAIL_BIT,pdFALSE,pdFALSE,portMAX_DELAY);/* xEventGroupWaitBits() returns the bits before the call returned, hence we can test which event actually* happened. */if (bits & WIFI_CONNECTED_BIT) {ESP_LOGI(TAG, "connected to ap SSID:%s password:%s",EXAMPLE_ESP_WIFI_SSID, EXAMPLE_ESP_WIFI_PASS);} else if (bits & WIFI_FAIL_BIT) {ESP_LOGI(TAG, "Failed to connect to SSID:%s, password:%s",EXAMPLE_ESP_WIFI_SSID, EXAMPLE_ESP_WIFI_PASS);} else {ESP_LOGE(TAG, "UNEXPECTED EVENT");}
}// 客户端处理任务
void client_task(void *pvParameters)
{client_params_t *params = (client_params_t *)pvParameters;int sock = params->socket;struct sockaddr_in addr = params->addr;free(pvParameters); // 释放分配的内存char addr_str[128];inet_ntoa_r(addr.sin_addr, addr_str, sizeof(addr_str) - 1);ESP_LOGI(TAG, "客户端任务启动: IP=%s, 端口=%d", addr_str, ntohs(addr.sin_port));char rx_buffer[128];char tx_buffer[128];// 设置keepalive选项int keepAlive = 1;int keepIdle = KEEPALIVE_IDLE;int keepInterval = KEEPALIVE_INTERVAL;int keepCount = KEEPALIVE_COUNT;setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, &keepAlive, sizeof(int));setsockopt(sock, IPPROTO_TCP, TCP_KEEPIDLE, &keepIdle, sizeof(int));setsockopt(sock, IPPROTO_TCP, TCP_KEEPINTVL, &keepInterval, sizeof(int));setsockopt(sock, IPPROTO_TCP, TCP_KEEPCNT, &keepCount, sizeof(int));// 设置接收超时struct timeval timeout;timeout.tv_sec = 10;timeout.tv_usec = 0;setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout));// 处理客户端数据while (1) {int len = recv(sock, rx_buffer, sizeof(rx_buffer) - 1, 0);if (len < 0) {if (errno == EAGAIN || errno == EWOULDBLOCK) {// 超时,继续等待continue;}ESP_LOGE(TAG, "接收数据错误: errno %d", errno);break;} else if (len == 0) {ESP_LOGI(TAG, "客户端 %s 断开连接", addr_str);break;} else {rx_buffer[len] = 0; // 添加null终止符ESP_LOGI(TAG, "从 %s 收到 %d 字节: %s", addr_str, len, rx_buffer);// 发送响应int tx_len = snprintf(tx_buffer, sizeof(tx_buffer), " server has received %d bytes", len);int sent = send(sock, tx_buffer, tx_len, 0);if (sent < 0) {ESP_LOGE(TAG, "发送失败: errno %d", errno);break;}}}// 关闭socketshutdown(sock, 0);close(sock);ESP_LOGI(TAG, "客户端 %s 处理结束", addr_str);vTaskDelete(NULL);
}// TCP服务器任务
void tcp_server_task(void *pvParameters)
{char addr_str[128];int addr_family = AF_INET;int ip_protocol = IPPROTO_IP;struct sockaddr_in server_addr;server_addr.sin_addr.s_addr = htonl(INADDR_ANY);server_addr.sin_family = AF_INET;server_addr.sin_port = htons(PORT);// 创建socketint listen_sock = socket(addr_family, SOCK_STREAM, ip_protocol);if (listen_sock < 0) {ESP_LOGE(TAG, "无法创建socket: errno %d", errno);vTaskDelete(NULL);return;}// 设置socket选项 (允许地址重用)int opt = 1;setsockopt(listen_sock, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));// 绑定socketint err = bind(listen_sock, (struct sockaddr *)&server_addr, sizeof(server_addr));if (err != 0) {ESP_LOGE(TAG, "socket绑定失败: errno %d", errno);close(listen_sock);vTaskDelete(NULL);return;}// 开始监听err = listen(listen_sock, EXAMPLE_MAX_STA_CONN);if (err != 0) {ESP_LOGE(TAG, "socket监听失败: errno %d", errno);close(listen_sock);vTaskDelete(NULL);return;}ESP_LOGI(TAG, "TCP服务器已启动,监听端口: %d", PORT);while (1) {ESP_LOGI(TAG, "等待新的客户端连接...");struct sockaddr_in client_addr;socklen_t client_len = sizeof(client_addr);int client_sock = accept(listen_sock, (struct sockaddr *)&client_addr, &client_len);if (client_sock < 0) {ESP_LOGE(TAG, "接受连接失败: errno %d", errno);continue;}// 将客户端IP转换为字符串inet_ntoa_r(client_addr.sin_addr, addr_str, sizeof(addr_str) - 1);ESP_LOGI(TAG, "新的客户端连接: IP=%s, 端口=%d", addr_str, ntohs(client_addr.sin_port));// 为客户端任务分配参数client_params_t *params = malloc(sizeof(client_params_t));if (params == NULL) {ESP_LOGE(TAG, "内存分配失败");close(client_sock);continue;}params->socket = client_sock;params->addr = client_addr;// 创建客户端任务if (xTaskCreate(client_task, "client_task", 4096, params, 5, NULL) != pdPASS) {ESP_LOGE(TAG, "无法创建客户端任务");free(params);close(client_sock);}}close(listen_sock);vTaskDelete(NULL);
}
void app_main(void)
{//Initialize NVSesp_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);ESP_LOGI(TAG, "ESP_WIFI_MODE_STA");wifi_init_sta();xEventGroupWaitBits(s_wifi_event_group, WIFI_CONNECTED_SUCCESS, pdFALSE, pdFALSE, portMAX_DELAY);vTaskDelay(1000 / portTICK_PERIOD_MS);// 创建TCP服务器任务xTaskCreate(tcp_server_task, "tcp_server", 4096, NULL, 5, NULL);
}

运行测试

I (1616) esp_netif_handlers: sta ip: 192.168.137.54, mask: 255.255.255.0, gw: 192.168.137.1
I (1616) wifi station: got ip:192.168.137.54
I (1616) wifi station: connected to ap SSID:zhaozhong password:12345678
I (2616) wifi station: TCP服务器已启动,监听端口: 8080
I (2616) wifi station: 等待新的客户端连接...
I (2616) main_task: Returned from app_main()
I (18386) wifi station: 新的客户端连接: IP=192.168.137.1, 端口=59883
I (18386) wifi station: 等待新的客户端连接...
I (18386) wifi station: 客户端任务启动: IP=192.168.137.1, 端口=59883
I (19296) wifi:<ba-add>idx:0 (ifx:0, d6:54:8b:b2:90:f3), tid:0, ssn:7, winSize:64
I (23296) wifi station:192.168.137.1 收到 20 字节: http://www.cmsoft.cn
I (28216) wifi station:192.168.137.1 收到 20 字节: http://www.cmsoft.cn
I (29146) wifi station:192.168.137.1 收到 20 字节: http://www.cmsoft.cn
I (58626) wifi station: 新的客户端连接: IP=192.168.137.230, 端口=49416
I (58626) wifi station: 等待新的客户端连接...
I (58626) wifi station: 客户端任务启动: IP=192.168.137.230, 端口=49416
I (58626) wifi station: 新的客户端连接: IP=192.168.137.230, 端口=49416
I (58626) wifi station: 等待新的客户端连接...
I (58626) wifi station: 客户端任务启动: IP=192.168.137.230, 端口=49416
I (78916) wifi station:192.168.137.230 收到 10 字节: 5588888811
I (87206) wifi station:192.168.137.230 收到 5 字节: hello
I (93646) wifi station:192.168.137.230 收到 5 字节: hello
I (98886) wifi station:192.168.137.1 收到 20 字节: http://www.cmsoft.cn
I (101326) wifi station:192.168.137.1 收到 20 字节: http://www.cmsoft.cn
I (106256) wifi station: 客户端 192.168.137.1 断开连接
  1. ESP32连接电脑创建的热点,并分配到了192.168.137.54地址。手机分配到了230地址
    在这里插入图片描述
  2. ESP32启动TCP服务器,然后用电脑网络助手和手机的网络助手连接。然后发送数据测试。
    在这里插入图片描述
  3. 可以实现多连接等功能。

二、 ESP32设置为静态IP

增加部分代码设置静态IP,然后在WiFi启动之前调用即可

// 静态IP配置
#define EXAMPLE_ESP_STATIC_IP      "192.168.137.100"
#define EXAMPLE_ESP_STATIC_GW      "192.168.137.1"
#define EXAMPLE_ESP_STATIC_NM      "255.255.255.0"// 设置静态IP的函数
void set_static_ip()
{esp_netif_t *netif = esp_netif_get_handle_from_ifkey("WIFI_STA_DEF");if (netif == NULL) {ESP_LOGE(TAG, "获取网络接口失败");return;}// 设置静态IP配置esp_netif_ip_info_t ip_info;memset(&ip_info, 0, sizeof(esp_netif_ip_info_t));ip_info.ip.addr = ipaddr_addr(EXAMPLE_ESP_STATIC_IP);ip_info.gw.addr = ipaddr_addr(EXAMPLE_ESP_STATIC_GW);ip_info.netmask.addr = ipaddr_addr(EXAMPLE_ESP_STATIC_NM);// 应用静态IP配置esp_netif_dhcpc_stop(netif);esp_netif_set_ip_info(netif, &ip_info);ESP_LOGI(TAG, "静态IP设置成功 (使用esp_netif)");
}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_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));wifi_config_t wifi_config = {.sta = {.ssid = EXAMPLE_ESP_WIFI_SSID,.password = EXAMPLE_ESP_WIFI_PASS,/* Authmode threshold resets to WPA2 as default if password matches WPA2 standards (password len => 8).* If you want to connect the device to deprecated WEP/WPA networks, Please set the threshold value* to WIFI_AUTH_WEP/WIFI_AUTH_WPA_PSK and set the password with length and format matching to* WIFI_AUTH_WEP/WIFI_AUTH_WPA_PSK standards.*/.threshold.authmode = ESP_WIFI_SCAN_AUTH_MODE_THRESHOLD,.sae_pwe_h2e = ESP_WIFI_SAE_MODE,.sae_h2e_identifier = EXAMPLE_H2E_IDENTIFIER,},};ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA) );ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_STA, &wifi_config) );// 在启动WiFi前设置静态IPset_static_ip();ESP_ERROR_CHECK(esp_wifi_start() );ESP_LOGI(TAG, "wifi_init_sta finished.");/* Waiting until either the connection is established (WIFI_CONNECTED_BIT) or connection failed for the maximum* number of re-tries (WIFI_FAIL_BIT). The bits are set by event_handler() (see above) */EventBits_t bits = xEventGroupWaitBits(s_wifi_event_group,WIFI_CONNECTED_BIT | WIFI_FAIL_BIT,pdFALSE,pdFALSE,portMAX_DELAY);/* xEventGroupWaitBits() returns the bits before the call returned, hence we can test which event actually* happened. */if (bits & WIFI_CONNECTED_BIT) {ESP_LOGI(TAG, "connected to ap SSID:%s password:%s",EXAMPLE_ESP_WIFI_SSID, EXAMPLE_ESP_WIFI_PASS);} else if (bits & WIFI_FAIL_BIT) {ESP_LOGI(TAG, "Failed to connect to SSID:%s, password:%s",EXAMPLE_ESP_WIFI_SSID, EXAMPLE_ESP_WIFI_PASS);} else {ESP_LOGE(TAG, "UNEXPECTED EVENT");}
}

进行测试

I (567) wifi:dp: 1, bi: 102400, li: 3, scale listen interval from 307200 us to 307200 us
I (577) wifi:set rx beacon pti, rx_bcn_pti: 0, bcn_timeout: 25000, mt_pti: 0, mt_time: 10000
I (587) esp_netif_handlers: sta ip: 192.168.137.100, mask: 255.255.255.0, gw: 192.168.137.1
I (597) wifi station: got ip:192.168.137.100
I (597) wifi station: connected to ap SSID:zhaozhong password:12345678
I (647) wifi:AP's beacon interval = 102400 us, DTIM period = 3
I (1607) wifi station: TCP服务器已启动,监听端口: 8080
I (1607) wifi station: 等待新的客户端连接...
I (1607) main_task: Returned from app_main()
I (8847) wifi station: 新的客户端连接: IP=192.168.137.1, 端口=54251
I (8847) wifi station: 等待新的客户端连接...
I (8847) wifi station: 客户端任务启动: IP=192.168.137.1, 端口=54251
I (11307) wifi:<ba-add>idx:0 (ifx:0, d6:54:8b:b2:90:f3), tid:0, ssn:6, winSize:64
I (13447) wifi station:192.168.137.1 收到 20 字节: http://www.cmsoft.cn
I (14987) wifi station:192.168.137.1 收到 20 字节: http://www.cmsoft.cn
I (15907) wifi station:192.168.137.1 收到 20 字节: http://www.cmsoft.cn
I (21127) wifi station:192.168.137.1 收到 20 字节: http://www.cmsoft.cn
I (21437) wifi station:192.168.137.1 收到 20 字节: http://www.cmsoft.cn

IP已经固定为192.168.137.100 静态IP设置正常。

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

热搜词