参考

platformio的esp32版的websocketServer.csdn

配置

idf.py menuconfig 
# 打开
(Top) → Component config → HTTP Server → [*] WebSocket server support  

wifi 配置共用

app_wifi.h


#ifndef _APP_WIFI_H_
#define _APP_WIFI_H_

#ifdef __cplusplus
extern "C" {
#endif

void app_wifi_main();

#ifdef __cplusplus
}
#endif

#endif

app_wifi.c

#include <string.h>

#include "freertos/FreeRTOS.h"
#include "freertos/event_groups.h"

#include "esp_wifi.h"
#include "esp_event.h"
#include "esp_netif.h"
#include "esp_log.h"
#include "nvs_flash.h"

#include "app_wifi.h"


// ============================================================
// WiFi 配置
// ============================================================

#define WIFI_SSID       "ming0"
#define WIFI_PASSWORD   "123456"
#define WIFI_MAX_RETRY  5


// ============================================================
// TAG
// ============================================================

static const char *TAG = "app_wifi";


// ============================================================
// WiFi 状态
// ============================================================

static int s_retry_num = 0;

static EventGroupHandle_t s_wifi_event_group = NULL;


// ============================================================
// Event Bits
// ============================================================

#define WIFI_CONNECTED_BIT BIT0
#define WIFI_FAIL_BIT      BIT1


// ============================================================
// WiFi Event Handler
// ============================================================

static void wifi_event_handler(
        void *arg,
        esp_event_base_t event_base,
        int32_t event_id,
        void *event_data)
{
    // ========================================================
    // STA 启动
    // ========================================================

    if (event_base == WIFI_EVENT &&
        event_id == WIFI_EVENT_STA_START)
    {
        ESP_LOGI(
                TAG,
                "WiFi STA started"
        );

        esp_wifi_connect();

        return;
    }


    // ========================================================
    // STA 断开
    // ========================================================

    if (event_base == WIFI_EVENT &&
        event_id == WIFI_EVENT_STA_DISCONNECTED)
    {
        if (s_retry_num < WIFI_MAX_RETRY)
        {
            esp_wifi_connect();

            s_retry_num++;

            ESP_LOGW(
                    TAG,
                    "WiFi disconnected, retry %d/%d",
                    s_retry_num,
                    WIFI_MAX_RETRY
            );
        }
        else
        {
            ESP_LOGE(
                    TAG,
                    "WiFi connect failed"
            );

            if (s_wifi_event_group != NULL)
            {
                xEventGroupSetBits(
                        s_wifi_event_group,
                        WIFI_FAIL_BIT
                );
            }
        }

        return;
    }


    // ========================================================
    // STA 获取 IP
    // ========================================================

    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)
        );


        ESP_LOGI(
                TAG,
                "Netmask: " IPSTR,
                IP2STR(&event->ip_info.netmask)
        );


        ESP_LOGI(
                TAG,
                "Gateway: " IPSTR,
                IP2STR(&event->ip_info.gw)
        );


        s_retry_num = 0;


        if (s_wifi_event_group != NULL)
        {
            xEventGroupSetBits(
                    s_wifi_event_group,
                    WIFI_CONNECTED_BIT
            );
        }

        return;
    }
}


// ============================================================
// 初始化 STA
// ============================================================

static void wifi_init_sta(void)
{
    wifi_config_t wifi_config = {
            0
    };


    // --------------------------------------------------------
    // SSID
    // --------------------------------------------------------

    strncpy(
            (char *)wifi_config.sta.ssid,
            WIFI_SSID,
            sizeof(wifi_config.sta.ssid) - 1
    );


    // --------------------------------------------------------
    // Password
    // --------------------------------------------------------

    strncpy(
            (char *)wifi_config.sta.password,
            WIFI_PASSWORD,
            sizeof(wifi_config.sta.password) - 1
    );


    // --------------------------------------------------------
    // WiFi STA 配置
    // --------------------------------------------------------

    ESP_ERROR_CHECK(
            esp_wifi_set_config(
                    WIFI_IF_STA,
                    &wifi_config
            )
    );


    ESP_LOGI(
            TAG,
            "STA configured"
    );


    ESP_LOGI(
            TAG,
            "SSID: %s",
            WIFI_SSID
    );
}


// ============================================================
// app_wifi_main
// ============================================================

void app_wifi_main(void)
{
    esp_err_t ret;


    // ========================================================
    // 1. 初始化 NVS
    // ========================================================

    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);


    // ========================================================
    // 2. 初始化 TCP/IP 网络栈
    // ========================================================

    ESP_ERROR_CHECK(
            esp_netif_init()
    );


    // ========================================================
    // 3. 创建默认 Event Loop
    // ========================================================

    ESP_ERROR_CHECK(
            esp_event_loop_create_default()
    );


    // ========================================================
    // 4. 创建 Event Group
    // ========================================================

    s_wifi_event_group =
            xEventGroupCreate();


    if (s_wifi_event_group == NULL)
    {
        ESP_LOGE(
                TAG,
                "Failed to create event group"
        );

        return;
    }


    // ========================================================
    // 5. 创建 STA 网络接口
    // ========================================================

    esp_netif_t *sta_netif =
            esp_netif_create_default_wifi_sta();


    if (sta_netif == NULL)
    {
        ESP_LOGE(
                TAG,
                "Failed to create STA netif"
        );

        return;
    }


    // ========================================================
    // 6. 初始化 WiFi Driver
    // ========================================================

    wifi_init_config_t cfg =
            WIFI_INIT_CONFIG_DEFAULT();


    ESP_ERROR_CHECK(
            esp_wifi_init(&cfg)
    );


    // ========================================================
    // 7. 注册 WiFi Event
    // ========================================================

    ESP_ERROR_CHECK(
            esp_event_handler_instance_register(
                    WIFI_EVENT,
                    ESP_EVENT_ANY_ID,
                    &wifi_event_handler,
                    NULL,
                    NULL
            )
    );


    // ========================================================
    // 8. 注册 IP Event
    // ========================================================

    ESP_ERROR_CHECK(
            esp_event_handler_instance_register(
                    IP_EVENT,
                    IP_EVENT_STA_GOT_IP,
                    &wifi_event_handler,
                    NULL,
                    NULL
            )
    );


    // ========================================================
    // 9. 配置 STA
    // ========================================================

    ESP_ERROR_CHECK(
            esp_wifi_set_mode(
                    WIFI_MODE_STA
            )
    );


    wifi_init_sta();


    // ========================================================
    // 10. 启动 WiFi
    // ========================================================

    ESP_ERROR_CHECK(
            esp_wifi_start()
    );


    // ========================================================
    // 11. 关闭 WiFi 省电
    // ========================================================

    ESP_ERROR_CHECK(
            esp_wifi_set_ps(
                    WIFI_PS_NONE
            )
    );


    ESP_LOGI(
            TAG,
            "WiFi started"
    );


    // ========================================================
    // 12. 等待连接结果
    // ========================================================

    EventBits_t bits =
            xEventGroupWaitBits(
                    s_wifi_event_group,
                    WIFI_CONNECTED_BIT |
                    WIFI_FAIL_BIT,
                    pdFALSE,
                    pdFALSE,
                    portMAX_DELAY
            );


    // ========================================================
    // 13. 判断连接结果
    // ========================================================

    if (bits & WIFI_CONNECTED_BIT)
    {
        ESP_LOGI(
                TAG,
                "Connected to WiFi"
        );
    }
    else if (bits & WIFI_FAIL_BIT)
    {
        ESP_LOGE(
                TAG,
                "Failed to connect to WiFi"
        );
    }


    // ========================================================
    // 14. 删除 Event Group
    // ========================================================

    vEventGroupDelete(
            s_wifi_event_group
    );

    s_wifi_event_group = NULL;


    ESP_LOGI(
            TAG,
            "app_wifi_main finished"
    );
}

webServer三选1

app_websocketServer.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "freertos/FreeRTOS.h"
#include "freertos/task.h"

#include "esp_log.h"
#include "esp_err.h"
#include "esp_http_server.h"

#include "app_wifi.h"


static const char *TAG = "WebSocket Server";

static httpd_handle_t server = NULL;


// ============================================================
// WebSocket 接收处理
//
// 客户端发什么,ESP32 回什么
// ============================================================

static esp_err_t handle_ws_req(httpd_req_t *req)
{
    // --------------------------------------------------------
    // WebSocket 握手
    // --------------------------------------------------------

    if (req->method == HTTP_GET)
    {
        ESP_LOGI(
                TAG,
                "WebSocket handshake done"
        );

        return ESP_OK;
    }


    // --------------------------------------------------------
    // 获取 Frame 长度
    // --------------------------------------------------------

    httpd_ws_frame_t ws_pkt;

    memset(
            &ws_pkt,
            0,
            sizeof(ws_pkt)
    );


    esp_err_t ret =
            httpd_ws_recv_frame(
                    req,
                    &ws_pkt,
                    0
            );


    if (ret != ESP_OK)
    {
        ESP_LOGE(
                TAG,
                "httpd_ws_recv_frame failed: %s",
                esp_err_to_name(ret)
        );

        return ret;
    }


    ESP_LOGI(
            TAG,
            "Received frame, type=%d, len=%d",
            ws_pkt.type,
            (int)ws_pkt.len
    );


    // --------------------------------------------------------
    // 分配 Payload
    // --------------------------------------------------------

    uint8_t *buf = NULL;


    if (ws_pkt.len > 0)
    {
        buf =
                calloc(
                        1,
                        ws_pkt.len + 1
                );


        if (buf == NULL)
        {
            ESP_LOGE(
                    TAG,
                    "malloc failed"
            );

            return ESP_ERR_NO_MEM;
        }


        ws_pkt.payload = buf;


        // ----------------------------------------------------
        // 接收真正的数据
        // ----------------------------------------------------

        ret =
                httpd_ws_recv_frame(
                        req,
                        &ws_pkt,
                        ws_pkt.len
                );


        if (ret != ESP_OK)
        {
            ESP_LOGE(
                    TAG,
                    "httpd_ws_recv_frame failed: %s",
                    esp_err_to_name(ret)
            );

            free(buf);

            return ret;
        }


        buf[ws_pkt.len] = '\0';


        ESP_LOGI(
                TAG,
                "Client -> ESP32: %s",
                (char *)buf
        );
    }


    // --------------------------------------------------------
    // Echo
    //
    // 客户端发什么
    // ESP32 回什么
    // --------------------------------------------------------

    if (ws_pkt.type == HTTPD_WS_TYPE_TEXT)
    {
        ret =
                httpd_ws_send_frame(
                        req,
                        &ws_pkt
                );


        if (ret != ESP_OK)
        {
            ESP_LOGE(
                    TAG,
                    "Echo failed: %s",
                    esp_err_to_name(ret)
            );
        }
        else
        {
            ESP_LOGI(
                    TAG,
                    "ESP32 -> Client: echo"
            );
        }
    }


    free(buf);


    return ret;
}


// ============================================================
// 每 1 秒广播一次
//
// 发送:
// 0 hello
// 1 hello
// 2 hello
// ...
// ============================================================

static void websocket_periodic_task(void *arg)
{
    uint32_t sequence = 0;


    while (1)
    {
        vTaskDelay(
                pdMS_TO_TICKS(1000)
        );


        if (server == NULL)
        {
            continue;
        }


        // ----------------------------------------------------
        // 生成消息
        // ----------------------------------------------------

        char message[64];


        snprintf(
                message,
                sizeof(message),
                "%lu hello",
                (unsigned long)sequence
        );


        sequence++;


        ESP_LOGI(
                TAG,
                "Broadcast: %s",
                message
        );


        // ----------------------------------------------------
        // WebSocket Frame
        // ----------------------------------------------------

        httpd_ws_frame_t ws_pkt;


        memset(
                &ws_pkt,
                0,
                sizeof(ws_pkt)
        );


        ws_pkt.type =
                HTTPD_WS_TYPE_TEXT;


        ws_pkt.payload =
                (uint8_t *)message;


        ws_pkt.len =
                strlen(message);


        // ----------------------------------------------------
        // 获取所有客户端
        // ----------------------------------------------------

        size_t fds =
                CONFIG_LWIP_MAX_LISTENING_TCP;


        int *client_fds =
                calloc(
                        fds,
                        sizeof(int)
                );


        if (client_fds == NULL)
        {
            ESP_LOGE(
                    TAG,
                    "Failed to allocate client_fds"
            );

            continue;
        }


        esp_err_t ret =
                httpd_get_client_list(
                        server,
                        &fds,
                        client_fds
                );


        if (ret != ESP_OK)
        {
            ESP_LOGE(
                    TAG,
                    "httpd_get_client_list failed: %s",
                    esp_err_to_name(ret)
            );

            free(client_fds);

            continue;
        }


        // ----------------------------------------------------
        // 广播
        // ----------------------------------------------------

        for (size_t i = 0; i < fds; i++)
        {
            int fd =
                    client_fds[i];


            int client_info =
                    httpd_ws_get_fd_info(
                            server,
                            fd
                    );


            if (client_info ==
                HTTPD_WS_CLIENT_WEBSOCKET)
            {
                ret =
                        httpd_ws_send_frame_async(
                                server,
                                fd,
                                &ws_pkt
                        );


                if (ret != ESP_OK)
                {
                    ESP_LOGW(
                            TAG,
                            "Send failed fd=%d: %s",
                            fd,
                            esp_err_to_name(ret)
                    );
                }
            }
        }


        free(client_fds);
    }
}


// ============================================================
// WebSocket Server
// ============================================================

httpd_handle_t setup_websocket_server(void)
{
    httpd_config_t config =
            HTTPD_DEFAULT_CONFIG();


    // --------------------------------------------------------
    // WebSocket /ws
    // --------------------------------------------------------

    httpd_uri_t ws = {
            .uri = "/ws",
            .method = HTTP_GET,
            .handler = handle_ws_req,
            .user_ctx = NULL,
            .is_websocket = true
    };


    // --------------------------------------------------------
    // 启动 HTTP Server
    // --------------------------------------------------------

    esp_err_t ret =
            httpd_start(
                    &server,
                    &config
            );


    if (ret != ESP_OK)
    {
        ESP_LOGE(
                TAG,
                "httpd_start failed: %s",
                esp_err_to_name(ret)
        );

        return NULL;
    }


    // --------------------------------------------------------
    // 注册 WebSocket
    // --------------------------------------------------------

    ret =
            httpd_register_uri_handler(
                    server,
                    &ws
            );


    if (ret != ESP_OK)
    {
        ESP_LOGE(
                TAG,
                "register /ws failed: %s",
                esp_err_to_name(ret)
        );

        return NULL;
    }


    ESP_LOGI(
            TAG,
            "WebSocket server started"
    );


    // --------------------------------------------------------
    // 创建周期发送任务
    // --------------------------------------------------------

    BaseType_t task_ret =
            xTaskCreate(
                    websocket_periodic_task,
                    "ws_periodic",
                    4096,
                    NULL,
                    5,
                    NULL
            );


    if (task_ret != pdPASS)
    {
        ESP_LOGE(
                TAG,
                "Failed to create websocket task"
        );
    }


    return server;
}


// ============================================================
// app_main
// ============================================================

void app_main(void)
{
    // --------------------------------------------------------
    // 连接现有路由器
    // --------------------------------------------------------

    app_wifi_main();


    // --------------------------------------------------------
    // 启动 WebSocket Server
    // --------------------------------------------------------

    setup_websocket_server();


    ESP_LOGI(
            TAG,
            "ESP32 WebSocket Server is running"
    );
}

app_udpServer.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <errno.h>

#include "freertos/FreeRTOS.h"
#include "freertos/task.h"

#include "esp_log.h"

#include "app_wifi.h"


// ============================================================
// UDP 配置
// ============================================================

#define UDP_PORT 5000
#define UDP_BUFFER_SIZE 1024


static const char *TAG = "UDP Server";


// ============================================================
// UDP Socket
// ============================================================

static int udp_socket = -1;


// ============================================================
// 最后一个 UDP 客户端
//
// UDP 没有连接的概念
// 所以记录最后一个给 ESP32 发数据的客户端
// ============================================================

static struct sockaddr_in client_addr;

static bool client_valid = false;


// ============================================================
// UDP 接收 + Echo
//
// 客户端发什么
// ESP32 回什么
// ============================================================

static void udp_receive_task(void *arg)
{
    char rx_buffer[UDP_BUFFER_SIZE];

    while (1)
    {
        struct sockaddr_in source_addr;

        socklen_t addr_len =
                sizeof(source_addr);


        // ----------------------------------------------------
        // 等待 UDP 数据
        // ----------------------------------------------------

        int len =
                recvfrom(
                        udp_socket,
                        rx_buffer,
                        sizeof(rx_buffer) - 1,
                        0,
                        (struct sockaddr *)&source_addr,
                        &addr_len
                );


        if (len < 0)
        {
            ESP_LOGE(
                    TAG,
                    "recvfrom failed errno=%d",
                    errno
            );

            continue;
        }


        rx_buffer[len] = '\0';


        // ----------------------------------------------------
        // 保存客户端地址
        // ----------------------------------------------------

        memcpy(
                &client_addr,
                &source_addr,
                sizeof(client_addr)
        );

        client_valid = true;


        // ----------------------------------------------------
        // 打印客户端地址
        // ----------------------------------------------------

        char addr_str[INET_ADDRSTRLEN];

        inet_ntop(
                AF_INET,
                &source_addr.sin_addr,
                addr_str,
                sizeof(addr_str)
        );


        ESP_LOGI(
                TAG,
                "Client %s:%d -> ESP32: %s",
                addr_str,
                ntohs(source_addr.sin_port),
                rx_buffer
        );


        // ----------------------------------------------------
        // Echo
        //
        // 客户端发什么
        // ESP32 回什么
        // ----------------------------------------------------

        int ret =
                sendto(
                        udp_socket,
                        rx_buffer,
                        len,
                        0,
                        (struct sockaddr *)&source_addr,
                        addr_len
                );


        if (ret < 0)
        {
            ESP_LOGE(
                    TAG,
                    "sendto failed errno=%d",
                    errno
            );
        }
        else
        {
            ESP_LOGI(
                    TAG,
                    "ESP32 -> Client: echo"
            );
        }
    }
}


// ============================================================
// 每 1 秒发送一次
//
// 发送:
//
// 0 hello
// 1 hello
// 2 hello
// 3 hello
// ...
//
// 发送给最后一个 UDP 客户端
// ============================================================

static void udp_periodic_task(void *arg)
{
    uint32_t sequence = 0;


    while (1)
    {
        vTaskDelay(
                pdMS_TO_TICKS(1000)
        );


        // ----------------------------------------------------
        // 还没有客户端
        // ----------------------------------------------------

        if (!client_valid)
        {
            continue;
        }


        // ----------------------------------------------------
        // 生成消息
        // ----------------------------------------------------

        char message[64];


        snprintf(
                message,
                sizeof(message),
                "%lu hello",
                (unsigned long)sequence
        );


        sequence++;


        ESP_LOGI(
                TAG,
                "Periodic send: %s",
                message
        );


        // ----------------------------------------------------
        // UDP 发送
        // ----------------------------------------------------

        int ret =
                sendto(
                        udp_socket,
                        message,
                        strlen(message),
                        0,
                        (struct sockaddr *)&client_addr,
                        sizeof(client_addr)
                );


        if (ret < 0)
        {
            ESP_LOGE(
                    TAG,
                    "Periodic send failed errno=%d",
                    errno
            );
        }
    }
}


// ============================================================
// 创建 UDP Server
// ============================================================

static void udp_server_start(void)
{
    // --------------------------------------------------------
    // 创建 UDP Socket
    // --------------------------------------------------------

    udp_socket =
            socket(
                    AF_INET,
                    SOCK_DGRAM,
                    IPPROTO_IP
            );


    if (udp_socket < 0)
    {
        ESP_LOGE(
                TAG,
                "Unable to create socket errno=%d",
                errno
        );

        return;
    }


    // --------------------------------------------------------
    // Server 地址
    // --------------------------------------------------------

    struct sockaddr_in server_addr;

    memset(
            &server_addr,
            0,
            sizeof(server_addr)
    );


    server_addr.sin_family =
            AF_INET;

    server_addr.sin_addr.s_addr =
            htonl(INADDR_ANY);

    server_addr.sin_port =
            htons(UDP_PORT);


    // --------------------------------------------------------
    // bind
    // --------------------------------------------------------

    int ret =
            bind(
                    udp_socket,
                    (struct sockaddr *)&server_addr,
                    sizeof(server_addr)
            );


    if (ret < 0)
    {
        ESP_LOGE(
                TAG,
                "bind failed errno=%d",
                errno
        );

        close(udp_socket);

        udp_socket = -1;

        return;
    }


    // --------------------------------------------------------
    // 启动接收任务
    // --------------------------------------------------------

    BaseType_t task_ret =
            xTaskCreate(
                    udp_receive_task,
                    "udp_receive",
                    4096,
                    NULL,
                    5,
                    NULL
            );


    if (task_ret != pdPASS)
    {
        ESP_LOGE(
                TAG,
                "Failed to create UDP receive task"
        );

        close(udp_socket);

        udp_socket = -1;

        return;
    }


    // --------------------------------------------------------
    // 启动 1 秒周期发送任务
    // --------------------------------------------------------

    task_ret =
            xTaskCreate(
                    udp_periodic_task,
                    "udp_periodic",
                    4096,
                    NULL,
                    5,
                    NULL
            );


    if (task_ret != pdPASS)
    {
        ESP_LOGE(
                TAG,
                "Failed to create UDP periodic task"
        );

        return;
    }


    ESP_LOGI(
            TAG,
            "UDP server started, port=%d",
            UDP_PORT
    );
}


// ============================================================
// app_main
// ============================================================

void app_main(void)
{
    // --------------------------------------------------------
    // 连接现有路由器
    // --------------------------------------------------------

    app_wifi_main();


    // --------------------------------------------------------
    // 启动 UDP Server
    // --------------------------------------------------------

    udp_server_start();


    ESP_LOGI(
            TAG,
            "ESP32 UDP Server is running"
    );
}

app_tcpServer.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <errno.h>

#include "freertos/FreeRTOS.h"
#include "freertos/task.h"

#include "esp_log.h"

#include "app_wifi.h"


// ============================================================
// TCP 配置
// ============================================================

#define TCP_PORT        5000
#define TCP_BUFFER_SIZE 1024


static const char *TAG = "TCP Server";


// ============================================================
// TCP Server Socket
// ============================================================

static int server_socket = -1;


// ============================================================
// 当前客户端 Socket
//
// 简单版本:只支持一个客户端
// ============================================================

static int client_socket = -1;


// ============================================================
// TCP 接收任务
//
// 客户端发什么
// ESP32 回什么
// ============================================================

static void tcp_receive_task(void *arg)
{
    char rx_buffer[TCP_BUFFER_SIZE];


    while (1)
    {
        // ----------------------------------------------------
        // 等待客户端连接
        // ----------------------------------------------------

        struct sockaddr_in client_addr;

        socklen_t addr_len =
                sizeof(client_addr);


        ESP_LOGI(
                TAG,
                "Waiting for client..."
        );


        client_socket =
                accept(
                        server_socket,
                        (struct sockaddr *)&client_addr,
                        &addr_len
                );


        if (client_socket < 0)
        {
            ESP_LOGE(
                    TAG,
                    "accept failed errno=%d",
                    errno
            );

            continue;
        }


        // ----------------------------------------------------
        // 获取客户端 IP
        // ----------------------------------------------------

        char addr_str[INET_ADDRSTRLEN];


        inet_ntop(
                AF_INET,
                &client_addr.sin_addr,
                addr_str,
                sizeof(addr_str)
        );


        ESP_LOGI(
                TAG,
                "Client connected: %s:%d",
                addr_str,
                ntohs(client_addr.sin_port)
        );


        // ----------------------------------------------------
        // 接收客户端数据
        // ----------------------------------------------------

        while (1)
        {
            int len =
                    recv(
                            client_socket,
                            rx_buffer,
                            sizeof(rx_buffer) - 1,
                            0
                    );


            // ------------------------------------------------
            // 接收失败
            // ------------------------------------------------

            if (len < 0)
            {
                ESP_LOGE(
                        TAG,
                        "recv failed errno=%d",
                        errno
                );

                break;
            }


            // ------------------------------------------------
            // 客户端主动断开
            // ------------------------------------------------

            if (len == 0)
            {
                ESP_LOGI(
                        TAG,
                        "Client disconnected"
                );

                break;
            }


            rx_buffer[len] =
                    '\0';


            ESP_LOGI(
                    TAG,
                    "Client -> ESP32: %s",
                    rx_buffer
            );


            // ------------------------------------------------
            // Echo
            //
            // 客户端发什么
            // ESP32 回什么
            // ------------------------------------------------

            int ret =
                    send(
                            client_socket,
                            rx_buffer,
                            len,
                            0
                    );


            if (ret < 0)
            {
                ESP_LOGE(
                        TAG,
                        "send failed errno=%d",
                        errno
                );

                break;
            }


            ESP_LOGI(
                    TAG,
                    "ESP32 -> Client: echo"
            );
        }


        // ----------------------------------------------------
        // 关闭客户端
        // ----------------------------------------------------

        close(client_socket);

        client_socket = -1;


        ESP_LOGI(
                TAG,
                "Client socket closed"
        );
    }
}


// ============================================================
// 每 1 秒发送一次
//
// 0 hello
// 1 hello
// 2 hello
// ...
// ============================================================

static void tcp_periodic_task(void *arg)
{
    uint32_t sequence = 0;


    while (1)
    {
        vTaskDelay(
                pdMS_TO_TICKS(1000)
        );


        // ----------------------------------------------------
        // 当前没有客户端
        // ----------------------------------------------------

        if (client_socket < 0)
        {
            continue;
        }


        // ----------------------------------------------------
        // 生成消息
        // ----------------------------------------------------

        char message[64];


        snprintf(
                message,
                sizeof(message),
                "%lu hello",
                (unsigned long)sequence
        );


        sequence++;


        ESP_LOGI(
                TAG,
                "Periodic send: %s",
                message
        );


        // ----------------------------------------------------
        // TCP 发送
        // ----------------------------------------------------

        int ret =
                send(
                        client_socket,
                        message,
                        strlen(message),
                        0
                );


        if (ret < 0)
        {
            ESP_LOGW(
                    TAG,
                    "Periodic send failed errno=%d",
                    errno
            );

            /*
             * 不要在这里 close()
             *
             * tcp_receive_task() 会检测到:
             *
             * recv() == 0
             *
             * 或 recv() < 0
             *
             * 然后负责关闭 socket。
             */
        }
    }
}


// ============================================================
// 启动 TCP Server
// ============================================================

static void tcp_server_start(void)
{
    // --------------------------------------------------------
    // 创建 TCP Socket
    // --------------------------------------------------------

    server_socket =
            socket(
                    AF_INET,
                    SOCK_STREAM,
                    IPPROTO_IP
            );


    if (server_socket < 0)
    {
        ESP_LOGE(
                TAG,
                "Unable to create socket errno=%d",
                errno
        );

        return;
    }


    // --------------------------------------------------------
    // Server 地址
    // --------------------------------------------------------

    struct sockaddr_in server_addr;

    memset(
            &server_addr,
            0,
            sizeof(server_addr)
    );


    server_addr.sin_family =
            AF_INET;


    server_addr.sin_addr.s_addr =
            htonl(INADDR_ANY);


    server_addr.sin_port =
            htons(TCP_PORT);


    // --------------------------------------------------------
    // bind
    // --------------------------------------------------------

    int ret =
            bind(
                    server_socket,
                    (struct sockaddr *)&server_addr,
                    sizeof(server_addr)
            );


    if (ret < 0)
    {
        ESP_LOGE(
                TAG,
                "bind failed errno=%d",
                errno
        );

        close(server_socket);

        server_socket = -1;

        return;
    }


    // --------------------------------------------------------
    // listen
    // --------------------------------------------------------

    ret =
            listen(
                    server_socket,
                    1
            );


    if (ret < 0)
    {
        ESP_LOGE(
                TAG,
                "listen failed errno=%d",
                errno
        );

        close(server_socket);

        server_socket = -1;

        return;
    }


    ESP_LOGI(
            TAG,
            "TCP server listening on port %d",
            TCP_PORT
    );


    // --------------------------------------------------------
    // TCP 接收任务
    // --------------------------------------------------------

    BaseType_t task_ret =
            xTaskCreate(
                    tcp_receive_task,
                    "tcp_receive",
                    4096,
                    NULL,
                    5,
                    NULL
            );


    if (task_ret != pdPASS)
    {
        ESP_LOGE(
                TAG,
                "Failed to create TCP receive task"
        );

        return;
    }


    // --------------------------------------------------------
    // 周期发送任务
    // --------------------------------------------------------

    task_ret =
            xTaskCreate(
                    tcp_periodic_task,
                    "tcp_periodic",
                    4096,
                    NULL,
                    5,
                    NULL
            );


    if (task_ret != pdPASS)
    {
        ESP_LOGE(
                TAG,
                "Failed to create TCP periodic task"
        );

        return;
    }


    ESP_LOGI(
            TAG,
            "TCP server started"
    );
}


// ============================================================
// app_main
// ============================================================

void app_main(void)
{
    // --------------------------------------------------------
    // 连接现有路由器
    // --------------------------------------------------------

    app_wifi_main();


    // --------------------------------------------------------
    // 启动 TCP Server
    // --------------------------------------------------------

    tcp_server_start();


    ESP_LOGI(
            TAG,
            "ESP32 TCP Server is running"
    );
}

测试

# ws 连接
ws://192.168.3.45/ws
# tcp或udp
192.168.3.45:5000
# 收到1次hello
<-1 hello
<-2 hello
...
<-n hello

# 发送回环
-> abc
<- abc



Logo

智能硬件社区聚焦AI智能硬件技术生态,汇聚嵌入式AI、物联网硬件开发者,打造交流分享平台,同步全国赛事资讯、开展 OPC 核心人才招募,助力技术落地与开发者成长。

更多推荐