ESP32作为一款集成了Wi-Fi和蓝牙功能的低成本微控制器,在物联网领域有着广泛的应用。今天我要分享的是一个基于ESP-IDF框架实现的WiFi热点(AP模式)与TCP服务器结合的实战项目。这个方案可以让ESP32设备同时具备无线接入点和网络服务器的双重功能,特别适合需要本地组网和实时数据传输的场景。
在实际项目中,我经常遇到这样的需求:若干个移动设备需要与一个中央控制器进行数据交互,但又不能依赖外部网络环境。比如在工业现场的数据采集、智能家居的本地控制、或者临时搭建的演示系统中。传统的解决方案要么需要路由器等额外设备,要么通信能力有限。而这个ESP32的AP+TCP方案完美解决了这些问题——它让ESP32自己成为网络枢纽,既能提供WiFi连接,又能处理多设备的并发通信。
虽然所有ESP32开发板理论上都支持这个功能,但根据我的实际测试经验,有以下建议:
ESP-IDF的环境配置有几个关键点需要注意:
安装完成后,建议先运行examples/get-started/hello_world测试基础环境是否正常。
核心配置结构体wifi_config_t中,AP模式需要关注以下参数:
c复制wifi_config_t wifi_config = {
.ap = {
.ssid = "ESP32_AP", // 热点名称
.ssid_len = strlen("ESP32_AP"),
.password = "12345678", // 密码,至少8字符
.channel = 6, // 信道选择
.authmode = WIFI_AUTH_WPA2_PSK, // 加密方式
.max_connection = 4, // 最大连接数
.beacon_interval = 100 // 信标间隔(ms)
}
};
几个经验参数:
正确的初始化顺序很关键:
常见错误是遗漏NVS初始化,会导致配置无法保存。
通过事件回调可以监控设备连接状态:
c复制ESP_ERROR_CHECK(esp_event_handler_instance_register(WIFI_EVENT,
ESP_EVENT_ANY_ID,
&wifi_event_handler,
NULL,
NULL));
static void wifi_event_handler(void* arg, esp_event_base_t event_base,
int32_t event_id, void* event_data) {
if (event_id == WIFI_EVENT_AP_STACONNECTED) {
wifi_event_ap_staconnected_t* event = (wifi_event_ap_staconnected_t*) event_data;
ESP_LOGI(TAG, "Station "MACSTR" joined, AID=%d",
MAC2STR(event->mac), event->aid);
} else if (event_id == WIFI_EVENT_AP_STADISCONNECTED) {
wifi_event_ap_stadisconnected_t* event = (wifi_event_ap_stadisconnected_t*) event_data;
ESP_LOGI(TAG, "Station "MACSTR" left, AID=%d",
MAC2STR(event->mac), event->aid);
}
}
我通常会维护一个连接设备列表,实时跟踪各设备状态。
c复制int listen_sock = socket(AF_INET, SOCK_STREAM, IPPROTO_IP);
c复制struct sockaddr_in server_addr;
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(3333);
server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
bind(listen_sock, (struct sockaddr *)&server_addr, sizeof(server_addr));
c复制listen(listen_sock, 5); // 5是等待队列长度
我采用select()模型处理多连接,相比多线程方案更节省资源:
c复制fd_set readfds;
FD_ZERO(&readfds);
FD_SET(listen_sock, &readfds);
struct timeval timeout = {
.tv_sec = 1,
.tv_usec = 0
};
int ret = select(listen_sock + 1, &readfds, NULL, NULL, &timeout);
if (ret > 0) {
if (FD_ISSET(listen_sock, &readfds)) {
// 有新连接
int new_sock = accept(listen_sock, NULL, NULL);
// 将new_sock加入连接池
}
// 检查其他socket是否有数据可读
for (int i = 0; i < max_clients; i++) {
if (client_sockets[i] > 0 && FD_ISSET(client_sockets[i], &readfds)) {
// 处理客户端数据
}
}
}
经过多次测试,我发现以下优化措施能显著提升性能:
c复制fcntl(sock, F_SETFL, fcntl(sock, F_GETFL) | O_NONBLOCK);
c复制int window_size = 8760;
setsockopt(sock, SOL_SOCKET, SO_RCVBUF, &window_size, sizeof(window_size));
建议采用这样的模块化结构:
code复制├── main/
│ ├── ap_tcp_server.c # 主逻辑
│ ├── wifi_ap.c # WiFi相关
│ ├── tcp_server.c # TCP相关
│ └── include/ # 头文件
├── components/ # 自定义组件
└── CMakeLists.txt
典型的事件循环结构:
c复制void app_main(void)
{
initialize_nvs();
start_wifi_ap();
create_tcp_server();
while (1) {
handle_tcp_connections();
vTaskDelay(100 / portTICK_PERIOD_MS);
}
}
这些参数经过实际测试验证:
现象:设备频繁断开重连
可能原因:
排查步骤:
优化方案:
通过TCP实现固件无线更新:
在实际项目中,这个基础框架已经支持了多种扩展应用。我曾经基于此开发过智能家居中控、工业数据采集器和互动展览系统等。关键是要根据具体需求调整参数和扩展功能模块。比如在智能家居项目中,我增加了JSON协议解析;在工业场景中,则强化了通信可靠性设计。