ESP32S3内网实现 WebSocket
WebSocket 是一种网络通信协议 ,它提供了在单个 TCP 连接上进行全双工、双向通信 的通道。它是为了在 Web 浏览器和服务器之间实现实时、高效的数据交换而设计的,是传统 HTTP 轮询技术的一种强大替代方案。
- 持久连接:
- 与 HTTP 请求不同(每个请求都需要建立和关闭连接),WebSocket 在客户端(如浏览器)和服务器之间建立一次连接 ,之后该连接会保持打开状态。
- 只要双方愿意,这个连接可以持续存在,允许数据在任何时候双向流动。
- 全双工通信:
- 一旦连接建立,客户端和服务器可以同时、独立地向对方发送数据。
- 服务器可以在有新信息时立即"推送"给客户端,无需客户端先发起请求。客户端也可以随时发送数据给服务器。
- 低开销:
- 建立连接时(通过一个特殊的 HTTP 握手过程),后续的数据交换使用非常轻量级的数据帧(frames) 进行传输。
- 相比于 HTTP 轮询(不断发送请求检查更新)或长轮询(挂起请求等待更新),WebSocket 大大减少了网络带宽消耗和延迟(尤其是往返延迟)。
- 基于事件驱动:
- 客户端和服务器端的代码通常基于事件模型编写。例如:
- 当连接成功建立时,触发
onopen
事件。 - 当收到对方发送的消息时,触发
onmessage
事件。 - 当连接关闭时,触发
onclose
事件。 - 当发生错误时,触发
onerror
事件。
- 当连接成功建立时,触发
- 客户端和服务器端的代码通常基于事件模型编写。例如:
- 握手过程:
- WebSocket 连接始于一个特殊的 HTTP 请求(称为"握手")。这个请求包含一个
Upgrade: websocket
头,表明客户端希望将连接升级到 WebSocket 协议。 - 如果服务器支持 WebSocket,它会返回一个 HTTP 101(Switching Protocols)响应,同意升级协议。
- 握手成功后,初始的 HTTP 连接就被"升级"为 WebSocket 连接,后续的通信都使用 WebSocket 协议的数据帧进行,不再是 HTTP。
- WebSocket 连接始于一个特殊的 HTTP 请求(称为"握手")。这个请求包含一个
- 支持文本和二进制数据:
- WebSocket 可以高效地传输纯文本(如 JSON、XML)和二进制数据(如图片、音频、视频流、自定义协议数据)。
为什么需要 WebSocket? (对比 HTTP)
- HTTP 的局限性:
- 单向性: 传统 HTTP 是"请求-响应"模型。客户端发起请求,服务器返回响应。服务器无法主动向客户端推送数据。
- 高延迟: 实现"实时"效果(如聊天、游戏、实时数据更新)需要客户端不断轮询服务器(频繁发送请求询问是否有新数据),这会产生大量不必要的请求和显著的延迟。
- 高开销: 每个 HTTP 请求/响应都包含完整的 HTTP 头信息(如 cookies、user-agent 等),对于频繁的小数据更新来说,这些头部信息是巨大的开销。
- WebSocket 的优势:
- 真正的实时性: 服务器可以瞬间将新数据推送给所有连接的客户端。
- 低延迟: 省去了建立连接的开销和轮询的等待时间。
- 低带宽消耗: 连接建立后,数据传输帧的头部信息极小。
- 高效的双向通信: 适合需要频繁、快速交互的应用。
典型应用场景:
- 实时聊天应用: 消息的即时发送和接收。
- 在线多人游戏: 玩家动作和游戏状态的实时同步。
- 协作编辑工具: 多个用户同时编辑文档时的实时更新。
- 实时数据仪表盘: 股票行情、体育赛事比分、服务器监控、物联网设备数据流。
- 在线拍卖/博彩: 实时出价和结果更新。
- 基于位置的服务: 实时位置共享和更新。
- 社交网络实时通知。
关键点总结:
- 协议: WebSocket 是一个独立的协议 (
ws://
或加密的wss://
)。 - 连接: 持久、长连接。
- 通信模式: 全双工、双向。
- 效率: 低延迟、低开销。
- 目的: 实现 Web 应用和服务器的实时、高效双向通信。
简单来说: WebSocket 就像在浏览器和服务器之间打开了一条专用的电话线。一旦拨通(握手成功),双方可以随时说话(发送数据)和收听(接收数据),不需要反复拨号(建立连接),通话(数据传输)也非常高效。这使得构建实时交互性强的 Web 应用变得容易且高效。
通过ESP32S3实现,首先确认功能实现:
ESP32S3作为服务器配置成AP模式
客户端(手机,电脑)连接ESP32S3热点形成局域网(内网)
连接web界面展示:
menuconfig选项配置:
开启WebSocket 服务器支持

增大网址请求头长度
代码部分讲解:
从主函数入口就可以管中窥豹,从宏观看待流程
c
void app_main(void) {
// 初始化非易失性存储器
ESP_ERROR_CHECK(nvs_flash_init());
// 初始化软AP模式
wifi_init_softap();
// 启动WebSocket服务器
start_websocket_server();
初始化非易失性存储器
初始化软AP模式
启动WebSocket服务器
}
总共分三个部分
- 初始化非易失性存储器(NVS)
- 初始化软AP模式(配置ESP32S3为AP模式,配置内网传输环境)
- 启动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)能推荐实习,恳请私信小弟给个机会,帮帮小弟,万分感谢!!!
联系方式:博文侧边栏微信二维码