当前位置: 首页 > news >正文

【stomp实战】websocket原理解析与简单使用

一、WebSocket 原理

WebSocket是HTML5提供的一种浏览器与服务器进行全双工通讯的网络技术,属于应用层协议。它基于TCP传输协议,并复用HTTP的握手通道。浏览器和服务器只需要完成一次握手,两者之间就直接可以创建持久性的连接, 并进行双向数据传输。

WebSocket 的出现就解决了半双工通信的弊端。它最大的特点是:服务器可以向客户端主动推动消息,客户端也可以主动向服务器推送消息。

在这里插入图片描述
WebSocket 特点的如下:
● 支持双向通信,实时性更强
● 可以发送文本,也可以发送二进制数据
● 建立在TCP协议之上,服务端的实现比较容易
● 数据格式比较轻量,性能开销小,通信高效
● 没有同源限制,客户端可以与任意服务器通信
● 协议标识符是ws(如果加密,则为wss),服务器网址就是 URL
● 与 HTTP 协议有着良好的兼容性。默认端口也是80和443,并且握手阶段采用 HTTP 协议,因此握手时不容易屏蔽,能通过各种 HTTP 代理服务器。

二、WebSocket 握手

WebSocket 服务端使用标准 TCP 套接字监听进入的连接。下文假定服务端监听 http://example.com 的 8000 端口,响应 http://example.com/chat 上的 GET 请求。

握手是 WebSocket 中 “Web”。它是从 HTTP 到 WebSocket 的桥梁。在握手过程中,协商连接的细节,并且如果行为不合法,那么任何一方都可以在完成前退出。服务端必须仔细理解客户端的所有要求,否则可能出现安全问题。

2.1 客户端握手请求

客户端通过联系服务端,请求 WebSocket 连接的方式,发起 WebSocket 握手流程。客户端发送带有如下请求头的标准 HTTP 请求(HTTP 版本必须是 1.1 或更高,并且请求方法必须是 GET):

GET /chat HTTP/1.1
Host: example.com:8000
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
Sec-WebSocket-Version: 13

在这里,客户端可以请求扩展和/或子协议。此外,也可以使用常见的请求头,比如 User-Agent、Referer、Cookie 或者身份验证请求头。这些请求头与 WebSocket 没有直接关联。

如果存在不合法的请求头,那么服务端应该发送 400 响应(“Bad Request”),并且立即关闭套接字。通常情况下,服务端可以在 HTTP 响应体中提供握手失败的原因 。如果服务端不支持该版本的 WebSocket,那么它应该发送包含它支持的版本的 Sec-WebSocket-Version 头。在上面的示例中,它指示 WebSocket 协议的版本为 13。

在请求头中,最值得关注的是 Sec-WebSocket-Key。接下来,将讲述它。

2.2 服务端握手响应

当服务端收到握手请求时,将发送一个特殊响应,该响应表明协议将从 HTTP 变更为 WebSocket。
在这里插入图片描述

该响应头大致如下(记住,每个响应头行以 \r\n 结尾,在最后一行的后面添加额外的 \r\n,以说明响应头结束):

HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=

此外,服务端可以在这里对扩展/子协议请求做出选择。Sec-WebSocket-Accept响应头很重要,服务端必须通过客户端发送的Sec-WebSocket-Key请求头生成它。具体的方式是,将客户端的Sec-WebSocket-Key与字符串"258EAFA5-E914-47DA-95CA-C5AB0DC85B11"(“魔法字符串”)连接在一起,然后对结果进行 SHA-1 哈希运算,最后返回哈希值的 Base64 编码。

因此,如果 Key 为"dGhlIHNhbXBsZSBub25jZQ==“,那么Sec-WebSocket-Accept响应头的值是"s3pPLMBiTxaQ9kYGzzhZRbK+xOo=”。服务端发送这些响应头后,握手完成,可以开始交换数据。

下面的 Python 代码根据Sec-WebSocket-Key请求头生成Sec-WebSocket-Accept响应头的值:

import typing
from hashlib import sha1
import base64SEC_WS_MAGIC_STRING: bytes = b"258EAFA5-E914-47DA-95CA-C5AB0DC85B11"def get_sec_ws_accept(sec_ws_key: typing.Union[bytes, str]) -> bytes:if isinstance(sec_ws_key, str):sec_ws_key = sec_ws_key.encode()return base64.b64encode(sha1(sec_ws_key + SEC_WS_MAGIC_STRING).digest())if __name__ == "__main__":assert get_sec_ws_accept(b"dGhlIHNhbXBsZSBub25jZQ==") == b"s3pPLMBiTxaQ9kYGzzhZRbK+

三、数据帧(Data Framing)

3.1 概览

在 WebSocket 协议中,使用一系列帧传输数据。为避免混淆网络中间人(比如拦截代理),以及出于安全考虑,客户端必须对发送给服务端的所有帧进行掩码(Mask)处理。(注意,无论 WebSocket 协议是否运行在 TLS 上,都需要进行掩码处理。)服务端在收到未进行掩码处理的帧时,必须关闭连接。在这种情况下,服务端可以发送状态码为 1002(协议错误)的关闭帧。服务端不得对发送给客户端的任何帧进行掩码处理。如果客户端检测到掩码帧,那么必须关闭连接。在这种情况下,可以使用状态码 1002(协议错误)。

基础帧协议定义了一种帧类型,包括操作码(Opcode)、有效载荷长度,以及“扩展数据”和“应用数据”的指定位置,它们一起定义“有效载荷数据”。一些位和操作码被保留,以供未来扩展协议。

在握手完成后,端点被发送关闭帧前,客户端和服务端可以随时传输数据帧。

3.2 基础帧协议

帧的格式如下图所示:
在这里插入图片描述

FIN:1 比特

表示该帧是消息中的最后一个分片。第一个分片也可能是最后一个分片。

RSV1、RSV2、RSV3:每个 1 比特

除非协商了定义非零值含义的扩展,否则必须为 0。如果收到非零值,并且没有协商的扩展定义该非零值的含义,那么接收端点必须使该 WebSocket 连接失败。

操作码:4 比特

定义对“有效载荷数据”的解释。如果收到未知操作码,那么接收端点必须使该 WebSocket 连接失败。定义的值如下:

%x0 表示延续帧
%x1 表示文本帧
%x2 表示二进制帧
%x3-7 为将来的非控制帧预留
%x8 表示连接关闭
%x9 表示 PING
%xA 表示 PONG
%xB-F 为将来的控制帧保留
掩码:1 比特

定义“有效载荷数据”是否被掩码处理。如果设置为 1,那么掩码键出现在 Masking-key 中,它用于解除“有效载荷数据”的掩码。从客户端发送到服务器的所有帧都将此位设置为 1。

有效载荷长度:7 比特,7+16 比特,或 7+64 比特

“有效载荷数据”的长度,单位是字节:如果设置为 0-125,那么它是有效载荷长度。如果设置为 126,那么接下来的 2 个字节(被解释为 16 位无符号整数)是有效载荷长度。如果设置为 127,那么接下来的 8 个字节(被解释为 64 位无符号整数,最高有效位必须为 0)是有效载荷长度。多字节长度量使用网络字节序表示。注意,在所有情况下,必须使用最小字节数编码长度,比如,124 字节长的字符串的长度不能编码为序列 126, 0, 124。有效载荷的长度是“扩展数据”的长度 + “应用数据”的长度。“扩展数据”的长度可能为 0,在这种情况下,有效载荷长度是“应用数据”的长度。

掩码键:0 或 4 字节

从客户端发送到服务端的所有帧必须通过包含在帧里的 32 位数值进行掩码处理。如果掩码位为 1,那么该字段存在,如果掩码位为 0,那么该字段不存在。

有效载荷数据:(x+y) 字节

“有效载荷数据”被定义为将 “扩展数据” 与 “应用数据” 连接在一起。

扩展数据:x 字节

除非已经协商了扩展,否则“扩展数据”为 0 字节。所有扩展必须指定"扩展数据"的长度,或者如何计算该长度,并且在开始握手期间,必须协商扩展的使用方式。如果存在,那么“扩展数据”包含在总有效载荷长度中。

应用数据:y 字节

任意“应用数据”,占用帧中“扩展数据”后面的剩余部分。“应用数据”的长度等于有效载荷长度减去“扩展数据”的长度。

3.3 消息分片(Message Fragmentation)
FIN 和 Opcode 字段共同协作,发送被拆分成单独帧的消息。这被称为消息分片。分片仅适用于 Opcode 0x0 到 0x2 的情况。

Opcode 说明帧的用途。如果为 0x1,那么有效载荷是文本。如果为 0x2,那么有效载荷是二进制数据。如果为 0x0,那么该帧是延续帧;这意味着服务端应该将该帧的有效载荷连接到其从该客户端收到的最后一个帧。在下面的草图中,服务端对发送文本消息的客户端做出响应。第一条消息以单个帧发送,而第二条消息用三个帧发送。下图仅显示客户端的 FIN 和 Opcode 细节:

Client: FIN=1, opcode=0x1, msg="hello"
Server: (process complete message immediately) Hi.
Client: FIN=0, opcode=0x1, msg="and a"
Server: (listening, new message containing text started)
Client: FIN=0, opcode=0x0, msg="happy new"
Server: (listening, payload concatenated to previous message)
Client: FIN=1, opcode=0x0, msg="year!"
Server: (process complete message) Happy new year to you too!

注意,第一个帧包含整个消息(FIN=1,并且opcode!=0x0),因此服务端可以按需处理或响应。客户端发送的第二个帧的有效载荷是文本(opcode=0x1),但整个消息尚未到达(FIN=0)。该消息的所有剩余部分使用延续帧(opcode=0x0)发送,并且消息的最后一帧用FIN=1标记。

四、Websocket的使用

4.1 客户端开发示例

const ws = new WebSocket('ws://localhost:8080/ws/zhangsan');
ws.onmessage = messageEvent => {console.log('onmessage: ', messageEvent.data)
}
ws.onopen = messageEvent => {console.log('onopen: ', messageEvent)
}
ws.onclose = messageEvent => {console.log('onclose: ', messageEvent)
}
ws.onerror = messageEvent => {console.log('onerror: ', messageEvent)
}// 发送消息
ws.send('hello world~')

在这里插入图片描述

4.2 服务端开发示例

4.2.1 J2EE的websocket

下面的示例是用javaee的接口来进行开发,而不是用springboot提供的实现
依赖引入

<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-websocket</artifactId>
</dependency>

配置类

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;@Configuration
public class WebSocketConfig {@Beanpublic ServerEndpointExporter serverEndpointExporter(){return new ServerEndpointExporter();}
}

服务端代码

import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;@Slf4j
@Component
@ServerEndpoint("/ws/{userName}")
public class MyServerEndpoint {public void sendMessage(Session session, String message) throws IOException {log.info("准备向客户端程序{}发送消息:{}", session.getId(), message);session.getBasicRemote().sendText(message);}@OnMessagepublic void onMessage(@PathParam("userName") String userName,String message, Session session) {log.info("收到来自客户端{}的消息! sessionId: {}, 消息:{}", userName, session.getId(), message);try {sendMessage(session, message);} catch (IOException e) {log.error("消息发送失败!", e);}}@OnOpenpublic void onOpen(@PathParam("userName") String userName, Session session) {log.info("客户端程序{}建立连接成功! sessionId:{}", userName, session.getId());}@OnClosepublic void onClose(@PathParam("userName") String userName, Session session, CloseReason closeReason) {log.info("客户端{}断开连接,原因:{}", userName, closeReason);}@OnErrorpublic void onError(Session session, Throwable throwable) {log.info("连接{}发生错误!", session.getId());throwable.printStackTrace();}
}

4.2.2 SpringFramework提供的websocket

依赖引入

<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-websocket</artifactId>
</dependency>

配置类

@Slf4j
@Configuration
@EnableWebSocket
public class SockConfig implements WebSocketConfigurer {@Overridepublic void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {registry.addHandler(echoWebSocketHandler(), "/ws/{userName}").setAllowedOriginPatterns("*").setHandshakeHandler(new DefaultHandshakeHandler()).addInterceptors(new HttpSessionHandshakeInterceptor() {@Overridepublic boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, Map<String, Object> attributes) throws Exception {// 认证等操作。。。return true;}});}public WebSocketHandler echoWebSocketHandler() {return new TextWebSocketHandler() {@Overrideprotected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {// 收到的信息String requestMsg = message.getPayload();System.out.println("服务器收到:" + requestMsg);// 组织响应信息String responseMsg = "服务器返回: " + requestMsg;System.out.println(responseMsg);TextMessage respMsg = new TextMessage(responseMsg.getBytes(StandardCharsets.UTF_8));// 返回给客户端session.sendMessage(respMsg);}};}
}

推荐使用springBoot提供的包来进行开发,封装了很多功能,简化了开发

相关文章:

【stomp实战】websocket原理解析与简单使用

一、WebSocket 原理 WebSocket是HTML5提供的一种浏览器与服务器进行全双工通讯的网络技术&#xff0c;属于应用层协议。它基于TCP传输协议&#xff0c;并复用HTTP的握手通道。浏览器和服务器只需要完成一次握手&#xff0c;两者之间就直接可以创建持久性的连接&#xff0c; 并…...

2024.1.30力扣每日一题——使循环数组所有元素相等的最少秒数

2024.1.30 题目来源我的题解方法一 暴力模拟&#xff08;无法通过&#xff09;方法二 哈希表数学 题目来源 力扣每日一题&#xff1b;题序&#xff1a;2808 我的题解 方法一 暴力模拟&#xff08;无法通过&#xff09; 直接暴力枚举。记录每一个元素所在的位置&#xff0c;然…...

【Java万花筒】数据魔术师:探索Java商业智能与数据可视化

开发者的数据魔杖&#xff1a;掌握Java商业智能工具的秘诀 前言 在当今信息爆炸的时代&#xff0c;数据已经成为企业决策和业务发展的重要驱动力。为了更好地理解和利用数据&#xff0c;商业智能&#xff08;BI&#xff09;和数据可视化工具变得至关重要。本文将介绍几种基于…...

python用yaml装参数并支持命令行修改

效果&#xff1a; 将实验用的参数写入 yaml 文件&#xff0c;而不是全部用 argparse 传&#xff0c;否则命令会很长&#xff1b;同时支持在命令行临时加、改一些参数&#xff0c;避免事必要在 yaml 中改参数&#xff0c;比较灵活&#xff08;如 grid-search 时遍历不同的 loss…...

第59讲订单数据下拉实现

import com.baomidou.mybatisplus.extension.plugins.pagination.Page;/*** 订单查询 type值 0 全部订单 1待付款 2 待收货 3 退款/退货* param type* return*/RequestMapping("/list")public R list(Integer type,Integer page,Integer pageSize){System.out.pri…...

[当人工智能遇上安全] 11.威胁情报实体识别 (2)基于BiGRU-CRF的中文实体识别万字详解

您或许知道&#xff0c;作者后续分享网络安全的文章会越来越少。但如果您想学习人工智能和安全结合的应用&#xff0c;您就有福利了&#xff0c;作者将重新打造一个《当人工智能遇上安全》系列博客&#xff0c;详细介绍人工智能与安全相关的论文、实践&#xff0c;并分享各种案…...

16:定时器和计数器

定时器和计数器 1、定时器和计数器的介绍2、定时器是如何工作3、寄存器4、51单片机定时器简介&#xff08;数据手册&#xff09;5、定时器中的寄存器&#xff08;数据手册&#xff09;5.1、TCON&#xff08;定时器控制寄存器&#xff09;5.2、TMOD&#xff08;工作模式寄存器&a…...

c#通过ExpressionTree 表达式树实现对象关系映射

//反射expression实现对象自动映射 void Main() {Person p1new(){Id1,Name"abc"};var persondto p1.MapTo<Person, PersonDto>();Console.WriteLine($"id:{persondto.Id}-name:{persondto.Name}"); }public static class AutoMapperExs { public s…...

《动手学深度学习(PyTorch版)》笔记7.2

注&#xff1a;书中对代码的讲解并不详细&#xff0c;本文对很多细节做了详细注释。另外&#xff0c;书上的源代码是在Jupyter Notebook上运行的&#xff0c;较为分散&#xff0c;本文将代码集中起来&#xff0c;并加以完善&#xff0c;全部用vscode在python 3.9.18下测试通过&…...

【MySQL进阶之路】BufferPool 生产环境优化经验

欢迎关注公众号&#xff08;通过文章导读关注&#xff1a;【11来了】&#xff09;&#xff0c;及时收到 AI 前沿项目工具及新技术的推送&#xff01; 在我后台回复 「资料」 可领取编程高频电子书&#xff01; 在我后台回复「面试」可领取硬核面试笔记&#xff01; 文章导读地址…...

Vim工具使用全攻略:从入门到精通

引言 在软件开发的世界里&#xff0c;Vim不仅仅是一个文本编辑器&#xff0c;它是一个让你的编程效率倍增的神器。然而&#xff0c;对于新手来说&#xff0c;Vim的学习曲线似乎有些陡峭。本文将手把手教你如何从Vim的新手逐渐变为高手&#xff0c;深入理解Vim的操作模式&#…...

Chapter 8 - 7. Congestion Management in TCP Storage Networks

TCP Flow Monitoring versus I/O Flow Monitoring TCP flow monitoring shouldn’t be confused with I/O flow monitoring because of the following reasons: TCP 流量监控不应与 I/O 流量监控混淆,原因如下: 1. TCP belongs to the transport layer (layer 4) of the OS…...

带你快速入门js高级-基础

1.作用域 全局 scriptxx.js 局部 函数作用域{} 块作用域 const let 2.闭包 函数外有权访问函数内的变量, 闭包可以延长变量生命周期 function 函数名 () {return function () {// 这里的变量不会立刻释放} }3.垃圾回收 不在使用(引用的变量), 防止占用内存&#xff0c;需要…...

数据结构与算法-链表(力扣附链接)

之前我们对C语言进行了一定的学习&#xff0c;有了一些基础之后&#xff0c;我们就可以学习一些比较基础的数据结构算法题了。这部分的知识对于我们编程的深入学习非常有用&#xff0c;对于一些基本的算法&#xff0c;我们学习之后&#xff0c;就可以参加一些编程比赛了&#x…...

多线程JUC:等待唤醒机制(生产者消费者模式)

&#x1f468;‍&#x1f393;作者简介&#xff1a;一位大四、研0学生&#xff0c;正在努力准备大四暑假的实习 &#x1f30c;上期文章&#xff1a;多线程&JUC&#xff1a;解决线程安全问题——synchronized同步代码块、Lock锁 &#x1f4da;订阅专栏&#xff1a;多线程&am…...

无人机动力系统高倍率锂聚合物电池介绍,无人机锂电池使用与保养,无人机飞行控制动力源详解

无人机电池使用及保养 电池是无人机飞行的动力来源,也是一个消耗品&#xff0c;对电池充分了解&#xff0c;采取正确的使用方法&#xff0c;妥善进行维护保养将有助于提高飞行的安全性、延长电池的使用寿命。以下将详细对电池的使用和管理进行讲解。 高倍率锂聚合物电池的含义…...

[BeginCTF]真龙之力

安装程序 双击安装 出现了安装失败的标签&#xff0c;开发者不允许测试。 查看Mainfest入口文件 <?xml version"1.0" encoding"utf-8"?> <manifest xmlns:android"http://schemas.android.com/apk/res/android" android:versionCo…...

手写分布式存储系统v0.3版本

引言 承接 手写分布式存储系统v0.2版本 &#xff0c;今天开始新的迭代开发。主要实现 服务发现功能 一、什么是服务发现 由于咱们的服务是分布式的&#xff0c;那从服务管理的角度来看肯定是要有一个机制来知道具体都有哪些实例可以提供服务。举个例子就是&#xff0c;张三家…...

除夕快乐!

打印的简单实现&#xff0c;祝大家新的一年万事顺意&#xff01; 龙年大吉&#xff01; #include <stdio.h> #include <windows.h> #include <string.h>int main() {const char* message "除夕快乐!";int i;for (i 0; i < strlen(message);…...

17:定时器编程实战

1、实验目的 (1)使用定时器来完成LED闪烁 (2)原来实现闪烁时中间的延迟是用delay函数实现的&#xff0c;在delay的过程中CPU要一直耗在这里不能去做别的事情。这是之前的缺点 (3)本节用定时器来定一个时间&#xff08;譬如0.3s&#xff09;&#xff0c;在这个定时器定时时间内…...

Fink CDC数据同步(五)Kafka数据同步Hive

6、Kafka同步到Hive 6.1 建映射表 通过flink sql client 建Kafka topic的映射表 CREATE TABLE kafka_user_topic(id int,name string,birth string,gender string ) WITH (connector kafka,topic flink-cdc-user,properties.bootstrap.servers 192.168.0.4:6668…...

ubuntu原始套接字多线程负载均衡

原始套接字多线程负载均衡是一种在网络编程中常见的技术&#xff0c;特别是在高性能网络应用或网络安全工具中。这种技术允许应用程序在多个线程之间有效地分配和处理网络流量&#xff0c;提高系统的并发性能。以下是关于原始套接字多线程负载均衡技术的一些介绍&#xff1a; …...

leetcode (算法)66.加一(python版)

需求 给定一个由 整数 组成的 非空 数组所表示的非负整数&#xff0c;在该数的基础上加一。 最高位数字存放在数组的首位&#xff0c; 数组中每个元素只存储单个数字。 你可以假设除了整数 0 之外&#xff0c;这个整数不会以零开头。 示例 1&#xff1a; 输入&#xff1a;digi…...

DataX源码分析 TaskGroupContainer

系列文章目录 一、DataX详解和架构介绍 二、DataX源码分析 JobContainer 三、DataX源码分析 TaskGroupContainer 四、DataX源码分析 TaskExecutor 五、DataX源码分析 reader 六、DataX源码分析 writer 七、DataX源码分析 Channel 文章目录 系列文章目录TaskGroupContainer初始…...

2024年华为OD机试真题-螺旋数字矩阵-Java-OD统一考试(C卷)

题目描述: 疫情期间,小明隔离在家,百无聊赖,在纸上写数字玩。他发明了一种写法: 给出数字个数n和行数m(0 < n ≤ 999,0 < m ≤ 999),从左上角的1开始,按照顺时针螺旋向内写方式,依次写出2,3...n,最终形成一个m行矩阵。 小明对这个矩阵有些要求: 1.每行数字的…...

红队打靶练习:PHOTOGRAPHER: 1

目录 信息收集 1、arp 2、nmap 3、nikto 目录扫描 1、gobuster 2、dirsearch WEB 信息收集 enum4linux smbclient 8000端口 CMS利用 信息收集 文件上传漏洞利用 提权 信息收集 get user.txt get flag 信息收集 1、arp ┌──(root㉿ru)-[~/kali] └─# a…...

【Linux】网络诊断 traceroute命令详解

目录 一、traceroute概述 1.1 traceroute命令简介 1.2 命令格式 1.3 原理 1.4 命令功能 二、使用实例 实例1&#xff1a;traceroute 用法简单、最常用的用法 实例2&#xff1a;跳数设置 实例3&#xff1a;设置探测数据包数量 实例4&#xff1a;显示IP地址&#xff0c…...

c#cad 创建-圆(二)

运行环境 vs2022 c# cad2016 调试成功 一、代码说明 这段代码是一个AutoCAD插件&#xff0c;用于在模型空间中创建一个圆形。 首先&#xff0c;我们需要定义一个命令类CreateCircleCommand&#xff0c;并在命名空间CreateCircleInCad中声明。 在CreateCircleCommand类中&a…...

面试高频知识点:2线程 2.1.5如何自定义实现一个线程池

在Java中&#xff0c;线程池是一种用于管理线程的机制&#xff0c;它可以有效地管理多个线程并且可以重复使用它们&#xff0c;从而减少了线程创建和销毁的开销&#xff0c;提高了线程的利用率。本文将介绍如何自定义实现一个简单的线程池&#xff0c;并提供相应的Java代码示例…...

【stm32】hal库学习笔记-ADC模数转换(超详细)

【stm32】hal库学习笔记-ADC模数转换&#xff08;超详细&#xff09; 本篇章介绍了ADC实现电压检测的三种方式 ADC原理及选型 ADC将连续的模拟电压信号转换为二进制的数字信号 选型参数 速度&#xff08;采样频率&#xff09; 功耗 精度 转换原理 ADC hal库驱动函数 普通…...

蓝桥杯基础知识6 pair

蓝桥杯基础知识6 pair pair 的定义和结构&#xff1a;在C中&#xff0c;pair是一个模板类&#xff0c;用于表示一对值的组合&#xff0c;头文件<utility>。 pair类 的定义&#xff1a; template<class T1, class T2> struct pair{T1 first; // 第一个值T2 seco…...

后端返回给前端的数据格式有哪些?

后端返回的数据格式有很多种&#xff0c;常见的包括JSON、XML、HTML、CSV等。这些格式各有特点&#xff0c;适用于不同的应用场景。 JSON&#xff08;JavaScript Object Notation&#xff09;&#xff1a;JSON是一种轻量级的数据交换格式&#xff0c;易于阅读和编写&#xff0c…...

Transformer的PyTorch实现之若干问题探讨(一)

《Transformer的PyTorch实现》这篇博文以一个机器翻译任务非常优雅简介的阐述了Transformer结构。在阅读时存在一些小困惑&#xff0c;此处权当一个记录。 1.自定义数据中enc_input、dec_input及dec_output的区别 博文中给出了两对德语翻译成英语的例子&#xff1a; # S: de…...

系统参数SystemParameters.MinimumHorizontalDragDistance

SystemParameters.MinimumHorizontalDragDistance 是一个系统参数&#xff0c;它表示在拖放操作中鼠标水平移动的最小距离。 当用户按下鼠标左键并开始移动鼠标时&#xff0c;系统会检查鼠标的水平移动距离是否超过了 SystemParameters.MinimumHorizontalDragDistance。只有当…...

平屋顶安装光伏需要注意哪些事项?

我国对于房屋建设的屋顶形式&#xff0c;主要有平屋顶、斜屋顶、曲面屋顶和多波式折板屋顶等。今天来讲讲在平屋顶安装光伏&#xff0c;需要注意的事项。 1.屋顶结构&#xff1a;在安装光伏系统之前&#xff0c;需要对屋顶结构进行评估&#xff0c;确保屋顶能够承受光伏系统的…...

《Git 简易速速上手小册》第7章:处理大型项目(2024 最新版)

文章目录 7.1 Git Large File Storage (LFS)7.1.1 基础知识讲解7.1.2 重点案例&#xff1a;在 Python 项目中使用 Git LFS 管理数据集7.1.3 拓展案例 1&#xff1a;使用 Git LFS 管理大型静态资源7.1.4 拓展案例 2&#xff1a;优化现有项目中的大文件管理 7.2 性能优化技巧7.2.…...

从0开始学Docker ---Docker安装教程

Docker安装教程 本安装教程参考Docker官方文档&#xff0c;地址如下&#xff1a; https://docs.docker.com/engine/install/centos/ 1.卸载旧版 首先如果系统中已经存在旧的Docker&#xff0c;则先卸载&#xff1a; yum remove docker \docker-client \docker-client-latest…...

嵌入式学习之Linux入门篇笔记——15,Linux编写第一个自己的命令

配套视频学习链接&#xff1a;http://【【北京迅为】嵌入式学习之Linux入门篇】 https://www.bilibili.com/video/BV1M7411m7wT/?p4&share_sourcecopy_web&vd_sourcea0ef2c4953d33a9260910aaea45eaec8 1.什么是命令&#xff1f; 命令就是可执行程序。 比如 ls -a…...

【C语言】SYSCALL_DEFINE3(socket, int, family, int, type, int, protocol)

一、SYSCALL_DEFINE3与系统调用 在Linux操作系统中&#xff0c;为了从用户空间跳转到内核空间执行特定的内核级操作&#xff0c;使用了一种机制叫做"系统调用"&#xff08;System Call&#xff09;。系统调用是操作系统提供给程序员访问和使用内核功能的接口。例如&…...

C++实现鼠标点击和获取鼠标位置(编译环境visual studio 2022)

1环境说明 2获取鼠标位置的接口 void GetMouseCurPoint() {POINT mypoint;for (int i 0; i < 100; i){GetCursorPos(&mypoint);//获取鼠标当前所在位置printf("% ld, % ld \n", mypoint.x, mypoint.y);Sleep(1000);} } 3操作鼠标左键和右键的接口 void Mo…...

Matplotlib绘制炫酷散点图:从二维到三维,再到散点图矩阵的完整指南与实战【第58篇—python:Matplotlib绘制炫酷散点图】

文章目录 Matplotlib绘制炫酷散点图&#xff1a;二维、三维和散点图矩阵的参数说明与实战引言二维散点图三维散点图散点图矩阵二维散点图进阶&#xff1a;辅助线、注释和子图三维散点图进阶&#xff1a;动画效果和交互性散点图矩阵进阶&#xff1a;调整样式和添加密度图总结与展…...

Docker-Learn(一)使用Dockerfile创建Docker镜像

1.创建并运行容器 编写Dockerfile&#xff0c;文件名字就是为Dockerfile 在自己的工作工作空间当中新建文件&#xff0c;名字为Docerfile vim Dockerfile写入以下内容&#xff1a; # 使用一个基础镜像 FROM ubuntu:latest # 设置工作目录 WORKDIR /app # 复制当前目…...

问题:银行账号建立以后,一般需要维护哪些设置,不包括() #学习方法#经验分享

问题&#xff1a;银行账号建立以后&#xff0c;一般需要维护哪些设置&#xff0c;不包括&#xff08;&#xff09; A&#xff0e;维护结算科目对照 B&#xff0e;期初余额初始化刷 C&#xff0e;自定义转账定义 D&#xff0e;对账单初始化 参考答案如图所示...

教授LLM思考和行动:ReAct提示词工程

ReAct&#xff1a;论文主页 原文链接&#xff1a;Teaching LLMs to Think and Act: ReAct Prompt Engineering 在人类从事一项需要多个步骤的任务时&#xff0c;而步骤和步骤之间&#xff0c;或者说动作和动作之间&#xff0c;往往会有一个推理过程。让LLM把内心独白说出来&am…...

FPGA_工程_按键控制的基于Rom数码管显示

一 信号 框图&#xff1a; 其中 key_filter seg_595_dynamic均为已有模块&#xff0c;直接例化即可使用&#xff0c;rom_8*256模块&#xff0c;调用rom ip实现。Rom_ctrl模块需要重新编写。 波形图&#xff1a; 二 代码 module key_fliter #(parameter CNT_MAX 24d9_999_99…...

WordPress Plugin HTML5 Video Player SQL注入漏洞复现(CVE-2024-1061)

0x01 产品简介 WordPress和WordPress plugin都是WordPress基金会的产品。WordPress是一套使用PHP语言开发的博客平台。该平台支持在PHP和MySQL的服务器上架设个人博客网站。WordPress plugin是一个应用插件。 0x02 漏洞概述 WordPress Plugin HTML5 Video Player 插件 get_v…...

【Kotlin】Kotlin基本数据类型

1 变量声明 var a : Int // 声明整数类型变量 var b : Int 1 // 声明整数类型变量, 同时赋初值为1 var c 1 // 声明整数类型变量, 同时赋初值为1 val d 1 // 声明整数类型常量, 值为1(后面不能改变d的值) 变量命名规范如下。 变量名可以由字母、数字、下划线&#xff08;_…...

UDP端口探活的那些细节

一 背景 商业客户反馈用categraf的net_response插件配置了udp探测, 遇到报错了&#xff0c;如图 udp是无连接的&#xff0c;无法用建立连接的形式判断端口。 插件最初的设计是需要配置udp的发送字符&#xff0c;并且配置期望返回的字符串&#xff0c; [[instances]] targets…...

拦截器配置,FeignClient根据业务规则实现微服务动态路由

文章目录 业务场景拦截器用法Open Feign介绍 业务场景 我们服务使用Spring Cloud微服务架构&#xff0c;使用Spring Cloud Gateway 作为网关&#xff0c;使用 Spring Cloud OpenFeign 作为服务间通信方式我们现在做的信控平台&#xff0c;主要功能之一就是对路口信号机进行管控…...

预测模型:MATLAB线性回归

1. 线性回归模型的基本原理 线性回归是统计学中用来预测连续变量之间关系的一种方法。它假设变量之间存在线性关系&#xff0c;可以通过一个或多个自变量&#xff08;预测变量&#xff09;来预测因变量&#xff08;响应变量&#xff09;的值。基本的线性回归模型可以表示为&…...