本文介绍: 1)本节主要是介绍在 ESP32 上实现 WebSocket 服务器。相比 HTTP 协议,WebSocket 通信协议除了可以双向通信、并且向多个客户端同时发送通知信息外,还可以提供持久连接,并且由于没有每个请求新建连接的开销,因此延迟较低。

ESP32-Web-Server编程– WebSocket 编程

概述

在前述 ESP32-Web-Server 实战编程-通过网页控制设备的 GPIO 中,我们创建一个基于 HTTP 协议的 ESP32 Web 服务器,每当浏览器向 Web 服务器发送请求我们将 HTML/CSS 文件提供给浏览器

在这里插入图片描述

使用 HTTP 服务器库的缺点是,**如果多个客户端连接到 Web 服务器,当 A 浏览器改变了网页内容比如点餐系统),它不会自动更新网页上的内容到所有客户端B、C。我们可以通过使用 WebSocket 通信协议解决问题。**例如,如果多个客户连接到 Web 服务器,并且任何一个客户更改设备的 GPIO 引脚的状态,则它将自动向所有连接的客户通知更改状态

在这里插入图片描述
相比 HTTP 协议,WebSocket 通信协议除了可以双向通信、并且向多个客户端同时发送通知信息外,可以提供持久连接,并且由于没有每个请求新建立连接的开销,因此延迟较低。

在这里插入图片描述

需求功能解析

本节演示如何在 ESP32 上实现一个WebSocket 服务器。示例仍旧以在网页控制一个 GPIO 为例子

与前述不同的是,通过 WebSocket 服务器,当多个浏览器访问服务器时,不同的浏览器之间可以及时接收到网页更新的信息。

示例解析

前端代码

示例中的 ESP32 WebSocket 服务前端代码dataindex.html 文件中,其主要提供两个功能

后端代码

通过 HTTP 建立 wrbsocket 握手

WebSocket 服务器通过 HTTP 协议握手然后开始使用 WebSocket 通信协议进行数据通信。因此,我们需要设置一个HTTP GET请求处理程序来完成最初始的建立握手的环节。
get_req_handler()函数用于响应握手阶段的 HTTP 请求

esp_err_t get_req_handler(httpd_req_t *req)
{
    int response;
    if(led_state)
    {
        sprintf(response_data, index_html, "ON");
    }
    else
    {
        sprintf(response_data, index_html, "OFF");
    }
    response = httpd_resp_send(req, response_data, HTTPD_RESP_USE_STRLEN);
    return response;
}

handle_ws_req(httpd_req_t *req) 负责处理从所有 Web 客户端发送到服务器的 WebSocket 请求

WebSocket 接收客户端的数据

函数 handle_ws_req(httpd_req_t *req) 负责处理从所有 Web 客户端发送到服务器的 WebSocket 请求(包括打开关闭处理通过 websocket 连接发送的数据)。

static esp_err_t handle_ws_req(httpd_req_t *req)

该函数首先检查请求方法是否是 HTTP 协议的 HTTP_GET,如果是,它将打印一条消息,指示 WebSocket 握手阶段(因为 WebSocket Web 服务器通过 HTTP 握手开始初始通信,然后遵循 WebSocket 通信协议)已完成,WebSocket 连接已打开,函数返回

if (req->method == HTTP_GET)
{
    ESP_LOGI(TAG, "Handshake done, the new connection was opened");
    return ESP_OK;
}

如果请求方法不是HTTP_GET,则在该示例中表示客户端请求正在发送 WebSocket 数据帧。将调用函数 httpd_ws_recv_frame() 来接收 WebSocket 数据帧并将其存储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 to get frame len with %d", ret);
        return ret;
    }

如果接收到数据长度不为零,则该函数将调用 calloc(1, ws_pkt.len + 1) 为 buf 变量分配内存,该变量将用于存储数据帧的有效负载然后,它再次调用 httpd_ws_recv_frame() 来检索数据框的有效负载并将其存储buf 变量中。该函数记录收到的消息和帧的长度

 if (ws_pkt.len)
    {
        buf = calloc(1, ws_pkt.len + 1);
        if (buf == NULL)
        {
            ESP_LOGE(TAG, "Failed to calloc memory for buf");
            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 with %d", ret);
            free(buf);
            return ret;
        }
        ESP_LOGI(TAG, "Got packet with message: %s", ws_pkt.payload);
    }

    ESP_LOGI(TAG, "frame len is %d", ws_pkt.len);

最后,该函数检查收到的消息是否为“切换”,如果是,则调用 trigger_async_send(req->handle, req) 函数来通知连接的其他客户端。

if (ws_pkt.type == HTTPD_WS_TYPE_TEXT &&
        strcmp((char *)ws_pkt.payload, "toggle") == 0)
    {
        free(buf);
        return trigger_async_send(req->handle, req);
    }
    return ESP_OK

总之,此函数通过处理 WebSocket 数据帧、接收请求中发送的消息以及通过向所有连接的客户端发送异步消息来处理消息来处理 WebSocket 请求。

WebSocket 发送方函数

以下两个函数响应 WebSocket 并将帧发送到所有连接的客户端:

static void ws_async_send(void *arg)
static esp_err_t trigger_async_send(httpd_handle_t handle, httpd_req_t *req)

trigger_async_send()负责调用 ws_async_send(),通过使用 httpd_queue_work()**对ws_async_send()进行排队并传递服务器句柄:

static esp_err_t trigger_async_send(httpd_handle_t handle, httpd_req_t *req)
{
    struct async_resp_arg *resp_arg = malloc(sizeof(struct async_resp_arg));
    resp_arg->hd = req->handle;
    resp_arg->fd = httpd_req_to_sockfd(req);
    return httpd_queue_work(handle, ws_async_send, resp_arg);
}

ws_async_send() 执行以下功能

示例效果

通过 WebSocket 实现多个浏览器客户端连接到 Web 服务器时可以同步更新同一个网页的内容

在这里插入图片描述

讨论

1)HTTP 传输协议与 WebSocket 在使用场景上有哪些不同?

HTTP在处理静态数据且不定期更新的应用程序中更可取。

WebSocket在处理实时数据的应用程序中更为可取。比如使用动态数据并期望持续和频繁更新的应用程序游戏应用程序社交软件必须与多个用户建立联系,这种类型的应用程序可以选择WebSocket来处理实时数据。

2)WebSocket 在前端中的 onload() 事件怎么理解

即在网页加载时,自动触发的函数,这是浏览器默认行为,是一个标准。还有其他称为“onOpen()“,“onClose()”,“onMessage()” 等的函数,它们处理WebSocket 上可能发生的不同事件

总结

1)本节主要是介绍在 ESP32 上实现 WebSocket 服务器。相比 HTTP 协议,WebSocket 通信协议除了可以双向通信、并且向多个客户端同时发送通知信息外,还可以提供持久连接,并且由于没有每个请求重新建立连接的开销,因此延迟较低。

资源链接

1)ESP32-Web-Server ESP-IDF系列博客介绍
2)对应示例的 code 链接点击直达代码仓库

3)下一篇:ESP32-Web-Server编程- 使用SSE 实时更新设备信息

(码字不易感谢点赞或收藏)

原文地址:https://blog.csdn.net/wangyx1234/article/details/134643851

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。

如若转载,请注明出处:http://www.7code.cn/show_12009.html

如若内容造成侵权/违法违规/事实不符,请联系代码007邮箱suwngjj01@126.com进行投诉反馈,一经查实,立即删除

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注