ESP32S3内网实现 WebSocket

ESP32S3内网实现 WebSocket

WebSocket 是一种网络通信协议 ,它提供了在单个 TCP 连接上进行全双工、双向通信 的通道。它是为了在 Web 浏览器和服务器之间实现实时、高效的数据交换而设计的,是传统 HTTP 轮询技术的一种强大替代方案。

  1. 持久连接:
    • 与 HTTP 请求不同(每个请求都需要建立和关闭连接),WebSocket 在客户端(如浏览器)和服务器之间建立一次连接 ,之后该连接会保持打开状态
    • 只要双方愿意,这个连接可以持续存在,允许数据在任何时候双向流动。
  2. 全双工通信:
    • 一旦连接建立,客户端和服务器可以同时、独立地向对方发送数据
    • 服务器可以在有新信息时立即"推送"给客户端,无需客户端先发起请求。客户端也可以随时发送数据给服务器。
  3. 低开销:
    • 建立连接时(通过一个特殊的 HTTP 握手过程),后续的数据交换使用非常轻量级的数据帧(frames) 进行传输。
    • 相比于 HTTP 轮询(不断发送请求检查更新)或长轮询(挂起请求等待更新),WebSocket 大大减少了网络带宽消耗和延迟(尤其是往返延迟)。
  4. 基于事件驱动:
    • 客户端和服务器端的代码通常基于事件模型编写。例如:
      • 当连接成功建立时,触发 onopen 事件。
      • 当收到对方发送的消息时,触发 onmessage 事件。
      • 当连接关闭时,触发 onclose 事件。
      • 当发生错误时,触发 onerror 事件。
  5. 握手过程:
    • WebSocket 连接始于一个特殊的 HTTP 请求(称为"握手")。这个请求包含一个 Upgrade: websocket 头,表明客户端希望将连接升级到 WebSocket 协议。
    • 如果服务器支持 WebSocket,它会返回一个 HTTP 101(Switching Protocols)响应,同意升级协议。
    • 握手成功后,初始的 HTTP 连接就被"升级"为 WebSocket 连接,后续的通信都使用 WebSocket 协议的数据帧进行,不再是 HTTP。
  6. 支持文本和二进制数据:
    • WebSocket 可以高效地传输纯文本(如 JSON、XML)和二进制数据(如图片、音频、视频流、自定义协议数据)。

为什么需要 WebSocket? (对比 HTTP)

  • HTTP 的局限性:
    • 单向性: 传统 HTTP 是"请求-响应"模型。客户端发起请求,服务器返回响应。服务器无法主动向客户端推送数据。
    • 高延迟: 实现"实时"效果(如聊天、游戏、实时数据更新)需要客户端不断轮询服务器(频繁发送请求询问是否有新数据),这会产生大量不必要的请求和显著的延迟。
    • 高开销: 每个 HTTP 请求/响应都包含完整的 HTTP 头信息(如 cookies、user-agent 等),对于频繁的小数据更新来说,这些头部信息是巨大的开销。
  • WebSocket 的优势:
    • 真正的实时性: 服务器可以瞬间将新数据推送给所有连接的客户端。
    • 低延迟: 省去了建立连接的开销和轮询的等待时间。
    • 低带宽消耗: 连接建立后,数据传输帧的头部信息极小。
    • 高效的双向通信: 适合需要频繁、快速交互的应用。

典型应用场景:

  • 实时聊天应用: 消息的即时发送和接收。
  • 在线多人游戏: 玩家动作和游戏状态的实时同步。
  • 协作编辑工具: 多个用户同时编辑文档时的实时更新。
  • 实时数据仪表盘: 股票行情、体育赛事比分、服务器监控、物联网设备数据流。
  • 在线拍卖/博彩: 实时出价和结果更新。
  • 基于位置的服务: 实时位置共享和更新。
  • 社交网络实时通知。

关键点总结:

  • 协议: WebSocket 是一个独立的协议 (ws:// 或加密的 wss://)。
  • 连接: 持久、长连接。
  • 通信模式: 全双工、双向。
  • 效率: 低延迟、低开销。
  • 目的: 实现 Web 应用和服务器的实时、高效双向通信。

简单来说: WebSocket 就像在浏览器和服务器之间打开了一条专用的电话线。一旦拨通(握手成功),双方可以随时说话(发送数据)和收听(接收数据),不需要反复拨号(建立连接),通话(数据传输)也非常高效。这使得构建实时交互性强的 Web 应用变得容易且高效。

通过ESP32S3实现,首先确认功能实现:

ESP32S3作为服务器配置成AP模式

客户端(手机,电脑)连接ESP32S3热点形成局域网(内网)

连接web界面展示:

开启WebSocket 服务器支持

增大网址请求头长度

代码部分讲解:

从主函数入口就可以管中窥豹,从宏观看待流程

c 复制代码
void app_main(void) {
    // 初始化非易失性存储器
    ESP_ERROR_CHECK(nvs_flash_init());
    // 初始化软AP模式
    wifi_init_softap();
    // 启动WebSocket服务器
    start_websocket_server();
    初始化非易失性存储器
初始化软AP模式
启动WebSocket服务器
}

总共分三个部分

  1. 初始化非易失性存储器(NVS)
  2. 初始化软AP模式(配置ESP32S3为AP模式,配置内网传输环境)
  3. 启动WebSocket服务器(处理连接事件)

核心在第三部分,先处理客户端发起的http get请求,将其升级为WebSocket通信

c 复制代码
// 启动WebSocket服务器
static httpd_handle_t start_websocket_server(void) {
    // 声明一个httpd_handle_t类型的变量server,用于存储httpd_start函数返回的句柄
    httpd_handle_t server = NULL;
    // 声明一个httpd_config_t类型的变量config,用于存储httpd_start函数需要的配置参数
    httpd_config_t config = HTTPD_DEFAULT_CONFIG();

    // 设置uri匹配函数为httpd_uri_match_wildcard
    config.uri_match_fn = httpd_uri_match_wildcard;
    // 设置最大uri处理器的数量为16
    config.max_uri_handlers = 16;
    // 设置最大响应头的数量为16
    config.max_resp_headers = 16;
    // 设置最大打开的socket数量为4
    config.max_open_sockets = 4;

    // 调用httpd_start函数启动http服务器,并将返回的句柄存储在server变量中
    if (httpd_start(&server, &config) == ESP_OK) {
        // 声明一个httpd_uri_t类型的变量ws_uri,用于存储websocket的uri信息
        httpd_uri_t ws_uri = {
            .uri = "/ws",
            .method = HTTP_GET,
            .handler = ws_handler,//握手阶段,成功后升级通信协议为WebSocket
            .user_ctx = NULL,
            .is_websocket = true
        };
        httpd_register_uri_handler(server, &ws_uri);

        httpd_uri_t index_uri = {
            .uri = "/",
            .method = HTTP_GET,
            .handler = index_get_handler,//// 处理根路径的GET请求,发送html文件
            .user_ctx = NULL
        };
        httpd_register_uri_handler(server, &index_uri);
    }
    return server;
}

在这里服务器(ESP32S3)发送html网页文件给客户端,客户端在网页实现WebSocket接口调用

源码分享:

https://github.com/jianzhiji/blog/blob/main/ESP32S3_websocket.zip

结束语:

如果文章对你有所帮助,可以帮我点一下左下角推荐该文,万分感谢

博主目前在广州,深圳寻找找嵌入式软件实习。

如有大佬(HR,BOSS)能推荐实习,恳请私信小弟给个机会,帮帮小弟,万分感谢!!!

联系方式:博文侧边栏微信二维码