WebSocket 通信说明与基于 ESP-IDF 的 WebSocket 使用
一、 WebSocket 出现的背景
最开始 客户端(Client) 和 服务器(Server) 通信使用的是 HTTP 协议,HTTP 协议有一个的缺陷为:通信只能由客户端(Client)发起。
在一些场景下,这种单向请求的特点,注定了当 服务器(Server) 有连续的状态变化时, 客户端(Client) 要获知就非常麻烦。 客户端(Client) 只能使用轮询的方式,即每隔一段时间,就发出一个询问,来了解 服务器(Server) 有没有新的信息,最典型的场景就是聊天室。
轮询的方式导致效率很低,非常浪费资源, 客户端(Client) 必须不停地发起连接,或者 HTTP 连接始终打开。为此工程师们一直在思考更好的解决方案,因此 WebSocket 就这样诞生了。
二、WebSocket 的优缺点
WebSocket 优势:
- 实时性: 由于 WebSocket 的持久化连接,它可以实现实时的数据传输,避免了 Web 应用程序需要不断地发送请求以获取最新数据的情况。
- 双向通信: WebSocket 协议支持双向通信,这意味着 服务器(Server) 可以主动向 客户端(Client) 发送数据,而不需要 客户端(Client) 发送请求。
- 减少网络负载: 由于 WebSocket 的持久化连接,它可以减少 HTTP 请求的数量,从而减少了网络负载。
WebSocket 的劣势:
- 需要浏览器和 服务器(Server) 都支持: WebSocket 是一种相对新的技术,需要浏览器和服务器都支持。一些旧的浏览器和 服务器(Server) 可能不支持 WebSocket。
- 需要额外的开销: WebSocket 需要在服务器上维护长时间的连接,这需要额外的开销,包括内存和 CPU。
- 安全问题: 由于 WebSocket 允许 服务器(Server) 主动向 客户端(Client) 发送数据,可能会存在安全问题。 服务器(Server) 必须保证只向合法的 客户端(Client) 发送数据。
三、WebSocket 协议概述
WebSocket 协议是一种基于 TCP
的协议,用于在 客户端(Client) 和 服务器(Server) 之间建立持久连接,并且可以在这个连接上实时地交换数据。WebSocket 协议有自己的握手协议,用于建立连接,也有自己的数据传输格式。
当 客户端(Client) 发送一个 WebSocket 请求时,服务器(Server) 将发送一个协议响应以确认请求。在握手期间, 客户端(Client) 和 服务器(Server) 将协商使用的协议版本、支持的子协议、支持的扩展选项等。一旦握手完成,连接将保持打开状态, 客户端(Client) 和 服务器(Server) 就可以在连接上实时地传递数据。
WebSocket 协议使用的是 双向数据传输,即 客户端(Client) 和 服务器(Server) 都可以在任意时间向对方发送数据,而不需要等待对方的请求。它支持传输 二进制数据 和 文本数据,并可以自由地在它们之间进行转换。
WebSocket 通信过程
一个 WebSocket 连接包含以下四个主要阶段:
1、连接建立阶段(Connection Establishment)
在这个阶段, 客户端(Client) 和 服务器(Server) 之间的 WebSocket 连接被建立。 客户端(Client) 发送一个 WebSocket 握手请求, 服务器(Server) 响应一个握手响应,然后连接就被建立了。握手过程 如下:
WebSocket 为了兼容 HTTP 协议,是在 HTTP 协议的基础之上进行升级得到的。在客户端(Client) 和 服务器(Server) 端建立 HTTP 连接之后,客户端(Client) 会向 服务器(Server) 端发送一个升级到 WebSocket 的协议,如下所示:
GET /chat HTTP/1.1
Host: example.com:8000
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
Sec-WebSocket-Version: 13
通过设置 Upgrade 和 Connection 这两个 header,表示准备升级到 WebSocket 了。
除了这里列的属性之外,其他的 HTTP 自带的 header 属性都是可以接受的。
当 服务器(Server) 端收到客户端(Client) 的请求之后,会返回给客户端(Client) 一个响应,告诉客户端(Client) 协议已经从 HTTP 升级到 WebSocket 了。返回的响应可能是这样的:
HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=
这里的 Sec-WebSocket-Accept 是根据客户端(Client) 请求中的 Sec-WebSocket-Key
来生成的。具体而言是将客户端(Client) 发送的 Sec-WebSocket-Key
和 字符串 “258EAFA5-E914-47DA-95CA-C5AB0DC85B11
” 进行连接。然后使用 SHA1
算法求得其 Hash
值,最后将 Hash
值进行 base64
编码即可,当 服务器(Server) 端返回 Sec-WebSocket-Accept
之后,客户端(Client) 可以对其进行校验,已完成整个握手过程。
2、连接开放阶段(Connection Open)
在这个阶段,WebSocket 连接已经建立并开放,客户端(Client) 和 服务器(Server) 可以在连接上互相发送数据。
3、连接关闭阶段(Connection Closing)
在这个阶段,一个 WebSocket 连接即将被关闭。它可以被客户端(Client) 或 服务器(Server) 发起,通过发送一个关闭帧来关闭连接。
4、连接关闭完成阶段(Connection Closed)
在这个阶段,WebSocket 连接已经完全关闭。客户端(Client) 和 服务器(Server) 之间的任何交互都将无效。
需要注意的是,WebSocket 连接在任何时候都可能关闭,例如网络故障、 服务器(Server) 崩溃等情况都可能导致连接关闭。因此,需要及时处理 WebSocket 连接关闭的事件,以确保应用程序的可靠性和稳定性。
WebSocket 的消息格式
WebSocket 的消息格式与 HTTP 请求和响应的消息格式有所不同。WebSocket 的消息格式可以是 文本 或 二进制数据,并且 WebSocket 消息的传输是在一个已经建立的连接上进行的,因此不需要再进行 HTTP 请求和响应的握手操作。
由图可知,WebSocket 的报文格式可以分为七大部分,分别是 1bit
的 FIN 标志位,3bit
的RSV 保留位,4bit
的 Opcode,1bit
的 Mask 标志位,7/7+16/7+64bit
的 payloadLen,可选字段 masking-key
,可选字段 payload
。具体解释下:
-
FIN 标志位:此标志位用于指示当前的帧是消息的最后一个分段。
- WebSocket 支持将长消息切割成若干帧发送,切分后,前边的帧的 FIN 字段均为
0
,最后一个帧的 FIN 为1
。 - 当消息没有分段时,这个帧便包含所有信息,FIN 标志位为1.【1bite】
- WebSocket 支持将长消息切割成若干帧发送,切分后,前边的帧的 FIN 字段均为
-
RSV1~3 :这是三个保留位,一般情况下为全
0
。- 当 客户端(Client) 、服务端协商采用 WebSocket 扩展时,这三个标志位可以
非 0
,且值的含义由扩展进行定义。 - 如果出现
非0
值但并未采用 WebSocket 扩展,连接出错。
- 当 客户端(Client) 、服务端协商采用 WebSocket 扩展时,这三个标志位可以
-
Opcode :
4bit
操作码,用于指示帧类型。-
Opcode 决定了如何解析后续的数据载荷部分,如果操作码是不认识的,接收端应该断开连接。可选的操作码如下:
%x0:表示一个延续帧。当 Opcode 为 0 时,表示本次数据传输采用了数据分片,当前收到的数据帧为其中一个数据分片。 %x1:表示这是一个文本帧(frame) %x2:表示这是一个二进制帧(frame) %x3-7:保留的操作代码,用于后续定义的非控制帧。 %x8:表示连接断开。 %x9:表示这是一个 ping 操作。 %xA:表示这是一个 pong 操作。 %xB-F:保留的操作代码,用于后续定义的控制帧。
-
其中注意 WebSocket 既可以传输文本数据,也可以传输二进制数据
-
-
Mask 标志位:指示帧的
payload
是否需要使用掩码覆盖。-
RFC6455 规定,当且仅当由客户端(Client) 向服务端发送的帧需要覆盖。
-
掩码覆盖的作用:解决 “缓冲区溢出”(忽略)
-
当 Mask 为
1
,但服务端接收的数据没有进行过掩码操作,服务端需要断开连接payload length:7位/7+16位(64k)/7+64位(超级大),单位是字节 模式区分: ①当7bite的payloadlength<126,此时为模式1 ② 7bite的payloadlength=126,16bite生效为模式2 ③ 7bite的payloadlength=126,64bite生效为模式3
-
masking-key
与mask
值有关,当 mask 为0
时,没有masking-key
; 为1
时,有4bit
的masking-key
-
-
payload-data :长度可变。包含扩展数据(x 字节)和应用数据(y 字节)
-
如果通信双方约定使用了 WebSocket 扩展,则扩展数据也存放于此,并声明扩展长度。
-
如果没有约定使用,则扩展数据为
0 字节
。
-
WebSocket 的报文格式中最重要的便是
Opcode
、payload length(三种模式)
,payload data
四、基于 esp-idf 如何使用 webSocket
如何使用
-
对于 esp-idf v5.0 以下版本, 有对应的 websocket 示例, 用户可以直接进行测试。
-
对于 esp-idf v5.0 以上版本, 提供了 esp_websocket_client 组件, 直接在对应的示例下面添加组件即可。
idf.py add-dependency "espressif/esp_websocket_client^1.2.3"
基于 ESP-IDF SDK 使用 Websocket 的案例:
使用 esp-idf v4.2.2 版本, 服务器(Server) 有时会异常断开, 模块会收到 服务器(Server) 发过来的 opcode=0x08
关闭帧, 这这种情况下设备要如何重新连接?这个机制是怎样的呢?
首先,op_code
为 0x08
是一个断开帧, 表示对端主动断开的, 我们是不需要在 WEBSOCKET_EVENT_DATA 里去判断 op_code
等于 0x08
的情况。在 WEBSOCKET CLOSED 事件中,内部会进行断开的处理,如果直接在 WEBSOCKET_EVENT_CLOSED 调用 esp_websocket_client_start(client)
接口重新连接 服务器(Server) , 则实际测试下来会进入到 close 事件里面, 但是并没有重新连接, 日志如下:
2024-09-27 12:10:14.783]# RECV ASCII>
[0;32mI (27116) WEBSOCKET: ====================Received opcode=1==================[0m
[0;33mW (27116) WEBSOCKET: ------> [3, "410212051", {}] <------[2024-09-27 12:10:21.160]# RECV ASCII>
[0;32mI (33506) uart_events: netStatus:7
[2024-09-27 12:10:22.466]# RECV ASCII>
[0;32mI (34796) WEBSOCKET: ====================Received opcode=8==================[0m
[0;32mI (34796) WEBSOCKET: WEBSOCKET_EVENT_CLOSED[0m
[2024-09-27 12:10:26.185]# RECV ASCII>
[0;31mE (38486) TRANSPORT_WS: Error read response for Upgrade header GET /HBE-123456 HTTP/1.1Connection: UpgradeHost: 0c6eeb3d0d512aa2.octt.openchargealliance.org:21128User-Agent: ESP32 Websocket ClientUpgrade: websocketSec-WebSocket-Version: 13Sec-WebSocket-Key: VMy5tg1Rv1Gr/P7HhLCTVw==Sec-WebSocket-Protocol: ocpp1.6[0m
[0;31mE (38506) WEBSOCKET_CLIENT: Error transport connect[0m
[0;31mE (38516) WEBSOCKET_CLIENT: esp_websocket_client_abort_connection(160): Websocket already stop
[2024-09-27 12:10:29.403]# RECV ASCII>
[0;32mI (41746) uart_events: netStatus:6
[2024-09-27 12:10:37.633]# RECV ASCII>
[0;32mI (49976) uart_events: netStatus:6
[2024-09-27 12:10:45.848]# RECV ASCII>
[0;32mI (58196) uart_events: netStatus:6
[2024-09-27 12:10:51.190]# RECV ASCII>
[0;31mE (63456) task_wdt: Task watchdog got triggered. The following tasks did not reset the watchdog in time:[0m
[0;31mE (63456) task_wdt: - IDLE (CPU 0)[0m
[0;31mE (63456) task_wdt: Tasks currently running:[0m
[0;31mE (63456) task_wdt: CPU 0: websocket_task[0m
[0;31mE (63456) task_wdt: CPU 1: IDLE[0m
[0;31mE (63456) task_wdt: Print CPU 0 (current core) backtrace
Backtrace: 0x4013BF6A:0x3FFBE920 0x40082A71:0x3FFBE940 0x4000BFED:0x3FFF1030 0x40093AAD:0x3FFF1040 0x40091698:0x3FFF1060 0x400917A8:0x3FFF10A0 0x400DD000:0x3FFF10C0 0x400938D9:0x3FFF10F0
[0;31mE (63456) task_wdt: Print CPU 1 backtrace[0m
Backtrace: 0x4008BFF1:0x3FFBEF2
再进一步调试发现是因为客户端(Client) 如果收到 0x08
的 opcode
, 它不仅仅只是断开之前的连接, 还会释放掉之前创建的 handle
,所以用户需要在 WEBSOCKET_EVENT_CLOSED 事件里创建好 handle
, 然后直接去做重新连接的操作, 参考如下代码:
case WEBSOCKET_EVENT_CLOSED:ESP_LOGI(TAG, "WEBSOCKET_EVENT_CLOSED");esp_websocket_client_config_t websocket_cfg = {};shutdown_signal_timer = xTimerCreate("Websocket shutdown timer", NO_DATA_TIMEOUT_SEC * 1000 / portTICK_PERIOD_MS,pdFALSE, NULL, shutdown_signaler);shutdown_sema = xSemaphoreCreateBinary();websocket_cfg.task_stack = 8192;websocket_cfg.uri = "ws://0c6eeb3d0d512aa2.octt.openchargealliance.org:21128/HBE-123456";websocket_cfg.subprotocol="ocpp1.6";ESP_LOGI(TAG, "Connecting to %s...", websocket_cfg.uri);esp_websocket_client_handle_t client = esp_websocket_client_init(&websocket_cfg);esp_websocket_register_events(client, WEBSOCKET_EVENT_ANY, websocket_event_handler, (void *)client);esp_websocket_client_start(client);break;}
修改代码之后, 在 服务器(Server) 收到 0x08
的 opcode
之后, 可以重新连接成功。
相关文章:
WebSocket 通信说明与基于 ESP-IDF 的 WebSocket 使用
一、 WebSocket 出现的背景 最开始 客户端(Client) 和 服务器(Server) 通信使用的是 HTTP 协议,HTTP 协议有一个的缺陷为:通信只能由客户端(Client)发起。 在一些场景下࿰…...
UE5 Compile Plugins | Rebuild from Source Manually | Unreal Engine | Tutorial
Step 1 Open Engine Folder H:\UE5\UE_5.3\Engine\Build\BatchFiles Step 2 Hold "Shift""Mouse Right Click"in Empty Area Step 3 Select "Open PowerShell window here .\RunUAT.bat BuildPlugin -plugin"H:\projects\MetaHuman光照2\plu…...
深度解析 Ansible:核心组件、配置、Playbook 全流程与 YAML 奥秘(下)
文章目录 六、playbook运行playbook方式Playbook VS ShellScripts忽略错误 ignore_errorshandlers和notify结合使用触发条件playbook中tags的使用playbook中变量的使用invertory参数模板templates迭代与条件判断迭代:with_items迭代嵌套子变量roles 六、playbook 运…...
langchain chroma 与 chromadb笔记
chromadb可独立使用也可搭配langchain 框架使用。 环境: python 3.9 langchain0.2.16 chromadb0.5.3 chromadb 使用示例 import chromadb from chromadb.config import Settings from chromadb.utils import embedding_functions# 加载embedding模型 en_embeddin…...
04 创建一个属于爬虫的主虚拟环境
文章目录 回顾conda常用指令创建一个爬虫虚拟主环境Win R 调出终端查看当前conda的虚拟环境创建 spider_base 的虚拟环境安装完成查看环境是否存在 为 pycharm 配置创建的爬虫主虚拟环境选一个盘符来存储之后学习所写的爬虫文件用 pycharm 打开创建的文件夹pycharm 配置解释器…...
xcode开发相关英语单词
创建项目: otheraudio unit extension app音频单元扩展应用程序generic kernel extension通用内核扩展installer plug-in安装程序插件instruments package仪器包iokit driveriokit驱动程序presence pane状态窗格screen saver屏幕保护程序...
etcd-v3.5release-(2)-STM
a.b.c表示a文件里的b类的方法c,注意a不一定是包名,因为文件名不一定等于包名 !!!!etcd在put的过程中使用的batchTxBuffered,这个事务是写bbolt数据库使用的事务,是对bbolt.Tx的一个…...
多系统萎缩锻炼如何好起来?
多系统萎缩(Multiple System Atrophy, MSA)是一种复杂的神经系统退行性疾病,影响着患者的自主神经系统、运动系统和平衡功能等多个方面。面对这一挑战,科学、合理的锻炼对于缓解症状、提高生活质量至关重要。本文将详细介绍多系统…...
非对称任意进制转换器(安卓)
除了正常进制转换,还可以输入、输出使用不同的数字符号,达成对数值进行加密的效果 点我下载APK安装包提取码:h4nw 使用unity开发。新建一个c#代码文件,把代码覆盖进去,再把代码文件添加给main camera即可。 using Sy…...
MySQL数据库安全与管理
1、创建两个新用户U_student1和U_student2,密码分别为1234和5678 create user U_student1@localhost identified by 1234, U_student2@localhost identified by 5678; 2、创建两个新用户的详细信息保存在MySQL数据库的user表中 use mysql; select user, host, authentication…...
python使用PyPDF2 和 pdfplumber操作PDF文件
文章目录 一、第三方库介绍二、基本使用1、拆分pdf2、合并pdf3、提取文字内容4、提取表格内容5、PDF加密6、PDF解密 一、第三方库介绍 Python 操作 PDF 会用到两个库,分别是:PyPDF2 和 pdfplumber。 PyPDF2 可以更好的读取、写入、分割、合并PDF文件&a…...
【vue2自定义指令】v-disabled 实现el-switch,el-button等elementUI禁用(disabled)效果
如果你搜过类似的功能,肯定看到过千篇一律的 // 实现按钮禁用el.disabled true// 增加 elementUI 的禁用样式类el.classList.add(is-disabled)但是这个方案明显对el-switch,不起作用,所以我这边直接把方案贴出来,不想了解具体原理…...
从容面对大规模作业:利用PMI提升作业启用和结束效率
1.进程管理瓶颈 随着集群规模的不断扩大和处理器性能的不断提升,高性能计算HPC(High Performance Computing)系统性能已经进入百亿亿次时代,进程管理是高性能计算的一个重要组成部分,传统进程管理已经不能满足海量处理器的管理需求ÿ…...
2024年认证杯SPSSPRO杯数学建模C题(第一阶段)云中的海盐解题全过程文档及程序
2024年认证杯SPSSPRO杯数学建模 C题 云中的海盐 原题再现: 巴黎气候协定提出的目标是:在2100年前,把全球平均气温相对于工业革命以前的气温升幅控制在不超过2摄氏度的水平,并为1.5摄氏度而努力。但事实上,许多之前的…...
burp(6)暴力破解与验证码识别绕过
声明! 学习视频来自B站up主 **泷羽sec** 有兴趣的师傅可以关注一下,如涉及侵权马上删除文章,笔记只是方便各位师傅的学习和探讨,文章所提到的网站以及内容,只做学习交流,其他均与本人以及泷羽sec团队无关&a…...
不同系统查看软件占用端口的方式
Windows 使用命令提示符(CMD) 打开命令提示符: 按 Win R 键打开“运行”对话框,输入 cmd 并按回车。为了执行某些命令,您可能需要以管理员身份运行命令提示符。可以通过右键点击“开始”按钮并选择“命令提示符(管理…...
【已解决】黑马点评项目中-实战篇11-状态登录刷新章节设置RefreshTokenInterceptor拦截器后登录异常的问题
黑马点评项目中-实战篇11-状态登录刷新章节设置RefreshTokenInterceptor拦截器后登录异常的问题 在 MvcConfig 文件中添加好RefreshTokenInterceptor拦截器 出现异常情况 按照验证码登录后,进入主页面,再点击“我的”,又跳入登录界面 原因…...
Artec Leo 3D扫描仪 革新家具行业的数字化展示【沪敖3D】
随着科技的飞速进步,三维扫描技术已被广泛应用于包括家居行业在内的多个行业。面对现代消费者对家居产品日益增长的个性化和多样化需求,传统的家居设计和展示方法已难以满足市场需求。三维扫描技术的出现,为家居行业带来了新的发展机遇&#…...
UG NX二次开发(Python)-UIStyler-选取点
提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 1、前言2、设计一个UI界面3、创建长方体的代码4、需要引入的库5、测试验证1、前言 采用Python语言进行UG NX二次开发的资料比较少,我本来不是很认可采用Python进行二次开发的,但是近期有读者咨询…...
Linux网络编程之---组播和广播
一.组播 1.概述 单播地址标识单个IP 接口,广播地址标识某个子网的所有IP 接口, 多播地址标识一组IP 接口。单播和广播是寻址方案的两个极端(要么单个要么全部), 多播则意在两者之间提供一种折中方案。多播数据报只应该由对它感兴趣的接口接收…...
[计算机网络] HTTP/HTTPS
一. HTTP/HTTPS简介 1.1 HTTP HTTP(超文本传输协议,Hypertext Transfer Protocol)是一种用于从网络传输超文本到本地浏览器的传输协议。它定义了客户端与服务器之间请求和响应的格式。HTTP 工作在 TCP/IP 模型之上,通常使用端口 …...
运动模糊效果
1、运动模糊效果 运动模糊效果,是一种用于 模拟真实世界中快速移动物体产生的模糊现象 的图像处理技术,当一个物体以较高速度移动时,由于人眼或摄像机的曝光时间过长,该物体会在图像中留下模糊的运动轨迹。这种效果游戏、动画、电…...
扫二维码进小程序的指定页面
草料二维码解码器 微信开发者工具 获取二维码解码的参数->是否登陆->跳转 options.q onLoad: function (options) {// console.log("options",options.q)if (options && options.q) {// 解码二维码携带的链接信息let qrUrl decodeURIComponent(optio…...
uniapp的生命周期
在 UniApp 中,生命周期函数是指在组件(如页面、视图等)创建和销毁过程中会自动触发的一些函数。UniApp 提供了多种生命周期函数,帮助开发者在适当的时机进行相关的逻辑处理。 UniApp 的生命周期函数可以分为 页面生命周期 和 组件…...
vue3-生命周期钩子函数
在 Vue 3 中,**生命周期函数**是指在组件的不同阶段自动执行的一些特殊函数。这些函数就像组件的“生老病死”的各个阶段,你可以在不同阶段执行不同的操作。 生命周期的主要阶段: 1. **创建阶段**(组件还没有出现在页面上&#x…...
科技云报到:数智化转型风高浪急,天翼云如何助力产业踏浪而行?
科技云报到原创。 捷径消亡,破旧立新,是今年千行百业的共同底色。 穿越产业周期,用数字化的力量重塑企业经营与增长的逻辑,再次成为数字化技术应用的主旋律,也是下一阶段产业投资的重点。 随着数字化转型行至“深水区…...
利用 360 安全卫士极速版关闭电脑开机自启动软件教程
在使用电脑的过程中,过多的开机自启动软件会严重拖慢电脑的开机速度,影响我们的使用体验。本教程中简鹿办公将详细介绍如何使用 360 安全卫士极速版关闭电脑开机自启动软件,让您的电脑开机更加迅速流畅。 一、打开 360 安全卫士极速版 在电…...
调用大模型api 批量处理图像 保存到excel
最近需要调用大模型,并将结果保存到excel中,效果如下: 代码: import base64 from zhipuai import ZhipuAI import os import pandas as pd from openpyxl import Workbook from openpyxl.drawing.image import Image from io i…...
【Spring 全家桶】Spring MVC 快速入门,开始web 更好上手(上篇) , 万字解析, 建议收藏 ! ! !
本篇会加入个人的所谓鱼式疯言 ❤️❤️❤️鱼式疯言:❤️❤️❤️此疯言非彼疯言 而是理解过并总结出来通俗易懂的大白话, 小编会尽可能的在每个概念后插入鱼式疯言,帮助大家理解的. 🤭🤭🤭可能说的不是那么严谨.但小编初心是能让更多人…...
Redisson看门狗机制
redis分布式锁我们需要手动为锁设置超时过期时间,但是这个时间不好判断,如果太短,持有锁的客户端还在执行业务,锁就超时释放了;如果太长了,持有锁的客户端释放锁失败,则其他客户端一直没法获取锁…...
LeetCode279. 完全平方数(2024冬季每日一题 27)
给你一个整数 n ,返回 和为 n 的完全平方数的最少数量 。 完全平方数 是一个整数,其值等于另一个整数的平方;换句话说,其值等于一个整数自乘的积。例如,1、4、9 和 16 都是完全平方数,而 3 和 11 不是。 …...
HTML礼物圣诞树
系列文章 序号目录1HTML满屏跳动的爱心(可写字)2HTML五彩缤纷的爱心3HTML满屏漂浮爱心4HTML情人节快乐5HTML蓝色爱心射线6HTML跳动的爱心(简易版)7HTML粒子爱心8HTML蓝色动态爱心9HTML跳动的爱心(双心版)1…...
【JVM】JVM基础教程(二)
上一篇:【JVM】JVM基础教程(一)-CSDN博客 类加载器 什么是类加载器(ClassLoader) 是Java虚拟机提供给应用程序去实现获取类和接口字节码数据的技术。 从这个定义可以得出结论:Java是允许开发者写点代码…...
Appium 安装问题汇总
好生气好生气,装了几天了, opencv4nodejs 和 mjpeg-consumer 就是装不了,气死我了不管了,等后面会装的时候再来完善,气死了气死了。 目录 前言 1、apkanalyzer.bat 2、opencv4nodejs 3、ffmpeg 4、mjpeg-consume…...
在网安中什么是白帽子
在网络安全领域,白帽子是指那些专门从事网络安全研究,帮助企业或个人发现并修复安全漏洞的专家。以下是对白帽子的详细解释: 一、定义与角色 白帽子是网络安全领域的术语,通常指那些具备专业技能和知识的网络安全专家。他们的工作…...
C++解析URL的方式
一、URL格式为http://192.168.80.166:6666/designResLib/test/test std::vector<CString> ThkCabRMaterialStaDlg::splitAddress(const CString& address) {std::vector<CString> result;CString remaining address;result.push_back(remaining.Left(remaini…...
【软件安全】软件安全设计规范,软件系统安全设计制度(Word原件)
1.1安全建设原则 1.2 安全管理体系 1.3 安全管理规范 1.4 数据安全保障措施 1.4.1 数据库安全保障 1.4.2 操作系统安全保障 1.4.3 病毒防治 1.5安全保障措施 1.5.1实名认证保障 1.5.2 接口安全保障 1.5.3 加密传输保障 1.5.4终端安全保障 软件全面文档清单涵盖以下核心内容&a…...
基于ZooKeeper搭建Hadoop高可用集群
ZooKeeper搭建Hadoop高可用集群 在之前安装的Hadoop3.3.6集群中HDFS NameNode 和 YARN ResourceManager 都是单节点,集群不具有高可用性。 HDFS 高可用架构 HDFS 高可用架构主要组件: Active NameNode 和 Standby NameNode: 两台 NameNode…...
华硕主板不能开启
正常流程: [主機板]BIOS如何設置主機板整合圖形(內顯)和獨立顯示卡同時顯示輸出 | 官方支援 | ASUS 台灣 如果开启了CSR兼容性模式,在BIOS里面,就必须关掉,才能支持多显示器,如下图显示的标识才会出现。...
[C++]构造函数和析构函数
一、构造函数 1.构造函数的基本概念 1.对构造函数的理解: 构造函数是类的一种特殊成员函数,其主要功能是在创建对象时进行初始化操作。它的名字与类名相同,并且没有返回值类型(不能是void)。例如,对于一个…...
查询品牌涉及两张表(brand、brand_admin_mapping)
文章目录 1、BrandController2、AdminCommonService3、BrandApiService3、BrandCommonService4、BrandSqlService涉及的表SQL 查询逻辑参数处理执行查询完整 SQL 逻辑参数映射总结 SELECT * FROM brand_admin_mapping WHERE admin_id 252SELECT * FROM brand WHERE id 44SELE…...
CVPR和其他2024顶会论文阅读(资源整理【1】)
CVPR 2024论文阅读(资源整理【1】) 一、3d 重建与建模论文1-Deformable 3D Gaussians for High-Fidelity Monocular Dynamic Scene Reconstruction论文2- 4D Gaussian Splatting for Real-Time Dynamic Scene Rendering论文3-GaussianDreamer: Fast Generation from Text to …...
数据库表约束完全指南:提升数据完整性和准确性
数据库表约束完全指南:提升数据完整性和准确性 在数据库设计中,表约束是确保数据完整性和准确性的关键工具。本文将详细介绍各种类型的表约束及其使用方法,包括非空约束、唯一约束、主键约束、外键约束、默认值约束、检查约束以及自动递增约…...
保姆级教程用vite创建vue3项目并初始化添加PrimeVue UI踩坑实录
文章目录 一、什么是PrimeVue二、详细教程1.添加PrimeVue2.配置main.js3.添加自动引入4.配置vite.config.js5.创建测试页面 一、什么是PrimeVue PrimeVue 是一个用于 Vue.js 3.x 开发的一款高质量、广受欢迎的 Web UI 组件库。 官网地址:https://primevue.org/ 二、…...
数据库索引
以下是关于数据库索引的详细介绍,包括其概念、优点和缺点,并附带丰富的例子: 一、什么是数据库索引 数据库索引是一种数据结构,类似于书籍的目录,它能够帮助数据库管理系统(DBMS)迅速定位和访问…...
硬件选型规则
光源选型: 先用型号中带H的,没有的选标准的. 光源和光源控制器的搭配需要确保接口一致。 根据型号表中的最佳工作距离和相机的尺寸。 光源控制器选型: 首先选择海康风格系列光源控制器考虑与光源的接口匹配。功率应该满足接近光源功率。检查是否退市…...
linux 架构详解
Linux 是一种开源的操作系统内核,最初由 Linus Torvalds 于 1991 年创建。它是一个基于 Unix 的操作系统内核,用于构建完整的操作系统。Linux 架构是指 Linux 操作系统的内部结构和组成组件的工作方式。 整体架构 Linux系统通常被看作是一个层次化的结…...
Mybatis 学习 之 XML 手册
目录 单次执行单次新增单次更新单次删除 批量执行批量新增批量更新for 循环执行更新for 循环生成多条 sql,一次执行 批量删除 参数传递预处理方式 (OGNL表达式 #{})数据类型转换 直接替换 (EL表达式 ${}) 安全 单次执行 单次新增 <insert id"insert"…...
平面直角坐标系
图1 平面直角坐标系 横轴为x,竖轴为y,x、y的交点为O。 表示一个点经常表示为( x, y ),如图上的红点( 2, 3 )。 图2 点( 2, 3 )...
K8S对接ceph的RBD块存储
1 PG数量限制问题 1.1 原因分析 1.还是老样子,先创建存储池,在初始化为rbd。 [rootceph141~]# ceph osd pool create wenzhiyong-k8s 128 128 Error ERANGE: pg_num 128 size 3 for this pool would result in 295 cumulative PGs per OSD (2067 tot…...