Espressif 玩转 WebSocket

2023-10-07 03:10
文章标签 玩转 websocket espressif

本文主要是介绍Espressif 玩转 WebSocket,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

本文仅针对 ESP32

ESP32 使用 WebSocket 进行通信的场景比较少,大部分使用的应用层协议是 MQTTHTTP。不过对于 WebSocket,基本的了解还是要的。最近正好有时间,就撸一下 WebSocket

本文只是简单的对 WebSocket 进行分析,如果想深入了解的话,建议还是参考 RFC6455。

文章目录

  • WebSocket 是什么?
    • WebSocket 与 HTTP 的关系?
    • WebSocket 与 Socket 的关系?
  • WebSocket 简单示例
    • 搭建 WebSocket 本地服务器
      • 启动 WebSocket 服务端
      • 启动 WebSocket 客户端
  • WebSocket 协议
    • 握手
    • 数据交互

WebSocket 是什么?

WebSocket 是一种网络通信协议。跟 MQTT、HTTP 协议一样,它也属于 TCP/IP 四层模型中的应用层协议。

WebSocket 协议在 2008 年诞生,2011 年成为国际标准。HTML5 开始提供的一种浏览器与服务器进行全双工通讯的网络技术。它基于 TCP 传输,并复用 HTTP 的握手。

WebSocket 与 HTTP 的关系?

对于 HTTP,我们都知道它具有以下两个特性:

  1. 无连接:每次 HTTP 连接仅仅处理一个请求。服务器返回客户端的请求后,这次的 HTTP 连接也就意味着断开了。该特性可以大大提高服务器的执行效率。
  2. 无状态:HTTP 协议对于请求/应答过程不保存状态信息。意味着后续的处理如果需要前面的信息,就只能通过重传来实现。该特性可以减轻服务器的记忆负担,提高服务器的响应速度。

这两个特性在理论上大大提高了服务器的执行效率和响应速度。但也掩盖不了 HTTP 协议的一个弊端,那就是通信只能由客户端发起。这在以前倒是没什么问题,可现在的应用对实时性的要求越来越高,典型的应用场景就是直播,网页游戏,股票交易等。虽然可以通过轮询的方式加以解决,但轮询的效率非常低,不停的轮询在无形之中又加重了服务器的负担,这与 HTTP 的设计初衷又背道而驰。

看到这里,肯定有读者想到了 HTTP 的长连接。没错,当一个 HTTP 的请求被服务器响应后,HTTP 基于的 TCP 连接不会被关闭。客户端如果想再次发送 HTTP 的请求,可以直接在该 TCP 连接上发送。相比较轮询的方式,长连接算是一种比较优雅的方式。HTTP 的长连接是在响应头中加入头部字段 Connection:keep-alive 来实现。但长连接不会永久保持连接,也有一个保持的时间。HTTP 的长连接本质上就是 TCP 的长连接

  • 相同点

    1. 均属于 TCP/IP 四层模型中的应用层协议。
    2. 均是基于 TCP
    3. WebSocketHTTP 有良好的兼容性,默认端口也是 80443
  • 不同点
    HTTP 是单向的,只能由客户端发起 Request 请求;WebSocket 是双向的。

  • 联系
    WebSocket 仅仅只是借 HTTP 来完成握手。握手成功之后,WebSocket 有其自有的帧进行通信。

WebSocket 与 Socket 的关系?

对于 Socket,我们都知道它仅仅是一个抽象概念,它将 TCP/IP 层操作抽象为几个简单的接口供应用程序调用。对于用户来说,仅仅需要调用几个 socket 接口就可以完成主机之间的通信。

Socket 也可以用来表示网络中一个连接的两端WebSocket 仅仅是借用了这个概念来表示网络中一个连接的两端,而这两端可以等视作浏览器和服务器

WebSocket 简单示例

Espressif 已经提供了 WebSocket 的 demo。不过在该 demo 中使用的服务器已经不在提供服务,所以可以使用公共的服务器或者在本地自己搭建一个服务器。本文选择后者。

echo.websocket.org

搭建 WebSocket 本地服务器

本文在 Windows 环境下搭建基于 nodejs 平台实现的 WebSocket 测试工具 wscat

参考官方说明:wscat

安装步骤:

  1. 安装 nodejs
  2. 安装完成后在命令行下输入以下命令全局安装 wscat
npm install -g wscat

启动 WebSocket 服务端

安装完成之后,输入以下命令在本地 8080 端口启动 WebSocket 服务。

wscat -l 8080

wscat listen

启动 WebSocket 客户端

在 WebSocket 目录下执行以下命令进行配置(设置 WebSocket 的 URL):

idf.py menuconfig

WebSocket URL config
将固件下载到 ESP32 上并运行,就可以看到在 WebSocket 服务端不断接收到从 ESP32 上发送来的文本数据。
WebSocket receive

WebSocket 协议

结合 Wireshark 抓包,可以简单的对 WebSocket 协议进行分析。
Wireshark packets

握手

  • 建立 TCP 连接

    这个不用过多的介绍,TCP 建立连接需要 3 次握手。包 23545 (SYN),包 23547 (SYN, ACK) 和包 24983 (ACK) 分别表示 TCP 的 3 次握手包。

  • 握手

    WebSocket 借助 HTTP 来完成握手。客户端首先需要发送握手包,握手包以 HTTP GET Request 的结构发送给服务端,服务端解析了之后以 HTTP Response 的结构发送给客户端,其中 Response 中的状态码为 101 表示握手成功。

WebSocket 协议文档中对客户端发送的握手请求包有如下要求:
1. 握手请求包必须为一个有效的 HTTP Request
2. Request Method 必须为 Get,Request Version 必须至少为 1.1 版本
3. 请求头部中必须包含一个 Host 键值对,如果未在请求头部中使用 port 键值对的话,那在 Host 所对应的值中必须指明端口号
4. 请求头部中必须包含一个 Upgrade 键值对,值必须为 websocket
5. 请求头部中必须包含一个 Connection 键值对,值必须为 Upgrade
6. 请求头部中必须包含一个 Sec-WebSocket-Key 键值对,值必须是随机产生的 16 字节,以 base64 编码
7. 如果客户端是浏览器,则请求头部中必须包含一个 Origin 键值对
8. 请求头部中必须包含一个 Sec-WebSocket-Version 键值对,值必须为 13
9. 请求头部中可以包含一个 Sec-WebSocket-Protocol 键值对
10. 请求头部中可以包含一个 Sec-WebSocket-Extensions 键值对

我们来看一下 ESP32 发送的用于握手的 GET Request 包,基本满足协议中对握手请求包的要求。
Handshark Get Request
如果服务端选择接收连接,它必须回复一个有效的 HTTP Response 包。

WebSocket 协议文档中对服务端回复的 HTTP Response 有如下要求:

  1. 状态码必须为 101,原因短语可以为 Switching Protocols
  2. 首部行中必须有 Upgrade 键,值为 websocket
  3. 首部行中必须有 Connection 键,值为 Upgrade
  4. 首部行中必须有 Sec-WebSocket-Accept 键,值是根据客户端 Get Request 中的Sec-WebSocket-Key 键值生成,流程是先经过 SHA-1 加密成 20 字节的数据,在将这些数据以 base64 编码。

我们来看一下 wscat 回复的 HTTP Response 包,基本满足协议中的要求。
Handshark HTTP Response

数据交互

客户端和服务端要进行数据通信,首先要了解的就是 WebSocket 中的数据格式。WebSocket 中的数据帧比较简单,格式如下:
Data Framing

  1. FIN: 1 bit

    用来指示该帧是否是整个要发送的消息的最后一帧。如果整个消息能通过一帧发送,则也要置位。

  2. RSV1, RSV2, RSV3: 1 bit

    保留。必须为 0。

  3. opcode: 4 bits

    操作码。是对 Payload Data 域的解释。 如果接收端接收到未定义的操作码,则必须结束 WebSocket 连接。

    定义
    %x0表明这一帧数据是上一帧数据的延续,这一帧是一个连续帧
    %x1表明这一帧数据是一个文本帧
    %x2表明这一帧数据是一个二进制数据帧
    %x3 - 7保留,适用于未来的非控制帧
    %x8表明这一帧是个断开连接帧
    %x9ping 帧
    %xApong 帧
    %xB - F保留,适用于未来的控制帧
  4. MASK: 1 bit

    掩码位。指明 Payload Data 域中的数据是否经过 XOR(异或) 运算。如果值为 1,则 Masking-key 域中的值用来还原经过 XOR(异或) 过的数据。所有从客户端发给服务端的帧必须置 1

  5. Payload len: 7 bits, 7 + 16 bits, 7 + 64 bits

    负载长度位,必须结合 Extended payload length 域一起指明 Payload Data 域中数据的长度,以字节为单位 。注意 Payload len 域和 Extended payload length 域中均采用网络字节序(大端模式)

    1. Payload len 域中的值在 [0, 125] 中时,该域中的值就代表实际的数据长度,此时 Extended payload length 域消失。Payload len 域后为 Masking-key 域。
    2. Payload len 域中的值在 126 时,该域中的值就表明后续的 Extended payload length 域为 16 bits。Payload Data 域中数据的长度由 Extended payload length 域指明。
    3. Payload len 域中的值在 127 时,该域中的值就表明后续的 Extended payload length 域为 64 bits。Payload Data 域中数据的长度由 Extended payload length 域指明。
  6. Masking-key: 0 bit 或 32 bits

    掩码钥匙位。 MASK 域为 1 时有效。所有从客户端发给服务端的帧 MASK 域必须置 1。换句话说 Masking-key 域就是专门用来服务服务端的。服务端需要该域中的 key 用来解码 Payload len 域中的数据。所有服务端发送给客户端的帧设置 MASK 域为 0,此时帧中的 Masking-key 域省略。

未完待续…

这篇关于Espressif 玩转 WebSocket的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/155680

相关文章

SpringBoot实现websocket服务端及客户端的详细过程

《SpringBoot实现websocket服务端及客户端的详细过程》文章介绍了WebSocket通信过程、服务端和客户端的实现,以及可能遇到的问题及解决方案,感兴趣的朋友一起看看吧... 目录一、WebSocket通信过程二、服务端实现1.pom文件添加依赖2.启用Springboot对WebSocket

Java Websocket实例【服务端与客户端实现全双工通讯】

Java Websocket实例【服务端与客户端实现全双工通讯】 现很多网站为了实现即时通讯,所用的技术都是轮询(polling)。轮询是在特定的的时间间隔(如每1秒),由浏览器对服务器发 出HTTP request,然后由服务器返回最新的数据给客服端的浏览器。这种传统的HTTP request 的模式带来很明显的缺点 – 浏 览器需要不断的向服务器发出请求,然而HTTP

秒变高手:玩转CentOS 7软件更换的方法大全

在 CentOS 7 中更换软件源可以通过以下步骤完成。更换源可以加快软件包的下载速度,特别是当默认源速度较慢时。以下是详细步骤: 前言 为了帮助您解决在使用CentOS 7安装不了软件速度慢的问题,我们推出了这份由浪浪云赞助的教程——“CentOS7如何更换软件源加快下载速度”。 浪浪云,以他们卓越的弹性计算、云存储和网络服务受到广泛好评,他们的支持和帮助使得我们可以将最前沿的技术知识分

springboot websocket 服务端

在Spring Boot中使用WebSocket实现服务端和Java客户端的实时通信,可以分为几个步骤来完成。这里将详细介绍服务端和Java客户端的具体实现。 服务端设置 添加依赖: 在pom.xml文件中添加Spring WebSocket的依赖。 <dependency><groupId>org.springframework.boot</groupId><artifactId>spr

全能AI神器!工作效率提升80倍!Zmo.ai带你玩转AI做图!

今天,我要给大家介绍一款神器:Zmo.ai。 这个平台简直是做图神器,集多种功能于一身,让你像专业人士一样轻松创建和编辑图像,不需要任何美术与设计基础,真的非常适合我们这些“手残党”! 我们只需单击按钮即可从文本或图像生成令人惊叹的 AI 艺术、图像、动漫和逼真的照片,最关键的是它的功能真的很全啊! Zmo.ai旗下产品分类: AI照片生成器 AI动漫生成器 AI照片编辑器 A

玩转Python Turtle库,实现满屏飘字的魔法!

前言     本文将教你如何使用Python的Turtle库,通过简单的编程实现满屏飘字的炫酷效果。无需复杂的编程知识,跟着我们的步骤,你也可以成为编程小达人! 效果展示 开发过程 一、准备工作 首先,确保你的电脑上已经安装了Python环境。然后,你需要安装或更新Turtle库(通常Python安装时自带了Turtle库)。 二、编写代码 接下来,我们将通过编写一个简单的P

Spring boot 项目作为客户端调用 服务端websocket

文章目录 java客户端请求websocketSpring boot 导入包客户端调用方法测试执行方法connectWebSocketHandshakeMessagesendHandshakeWebSocketConfig.queue.take方法对应实体类配置 yaml 资源WebSocketConfig 配置类注入配置websocketUrl:LinkedBlockingQueueLin

如何玩转保险行业场景下的存储和数据?

近年来,随着云计算、大数据、移动互联网、「联网+」等技术的飞速发展,我们身边的每个行业都在发生着巨大的变化。 保险行业也面临着竞争加剧、创新加速的局面,尤其是去年保监会提出所有保险公司都要实施双录系统,即投保时需要录音录像,这些变化对保险企业的信息系统提出了越来越高的要求。 本文从数据的存储、传输以及应用封装等角度分析了保险行业面临的挑战,并基于 QingCloud 完整的企业级云计算平台和服

WebSocket+Spring boot 构建一个完整消息服务

1、添加依赖 compile project(":faas-spring-boot-starter-data-websocket") 2、定义WebSocketHandler Socket 服务入口(Header接收 jwt-token 同应用登录的Token(直接解决鉴权问题),然后定义请求的自定义参数,方便后续消息推送、支持群发、私发、模糊匹配) @Component@WebSock

spring-websocket基于stomp实现websocket

目录 概述 后端代码 拦截器 HandshakeInterceptor拦截器 ChannelInterceptor拦截器   消息转换器  配置类  消息处理 广播模式   用户模式 自定义请求头 用户信息  ChannelInterceptor拦截器设置用户信息  DefaultHandshakeHandler的继承类中设置用户对象 前端代码 概述