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

websocket的介绍及springBoot集成示例

目录

一、什么是Websocket

二、Websocket特点

三、WebSocket与HTTP的区别

四、常见应用场景

五、SpringBoot集成WebSocket

1. 原生注解

2. Spring封装


一、什么是Websocket

        WebSocket 是一种在单个 TCP 连接上进行 全双工 通信的协议,它可以让客户端和服务器之间进行实时的双向通信。WebSocket 使用一个长连接,在客户端和服务器之间保持持久的连接,从而可以实时地发送和接收数据。

        在 WebSocket 中,客户端和服务器之间可以互相发送消息,客户端可以使用 JavaScript 中的 WebSocket API 发送消息到服务器,也可以接收服务器发送的消息。

二、Websocket特点


        简单来说,websocket 具有双向通信,实时性强,支持二进制,控制开销的特点。

  1. 协议标识符是ws(如果加密,则为wss),服务器网址就是 URL。
  2. 实时通信,服务器可以随时主动给客户端下发数据。
  3. 保持连接状态,Websocket需要先创建连接,所以是一种有状态的协议,之后通信时就可以省略部分状态信息。
  4. 控制开销,连接创建后,服务器和客户端之间交换数据时,用于协议控制的数据包头部相对较小。在不包含扩展的情况下,对于服务器到客户端的内容,此头部大小只有2至10字节(和数据包长度有关);对于客户端到服务器的内容,头部还需要加上额外的4字节的掩码。
  5. 实现简单,建立在 TCP 协议之上,服务器端的实现比较容易,并且没有同源限制,客户端可以与任意服务器通信。
  6. 支持二进制传输,Websocket定义了二进制帧,可以发送文本,也可以发送二进制数据。
  7. 与 HTTP 协议有着良好的兼容性。默认端口也是80和443,并且握手阶段采用 HTTP 协议,因此握手时不容易屏蔽,能通过各种 HTTP 代理服务器。
  8. 支持扩展,用户可以扩展协议、实现部分自定义的子协议,如部分浏览器支持压缩等。

三、WebSocket与HTTP的区别


        websocket和http都是基于TCP的应用层协议,使用的也是 80 端口(若运行在 TLS 之上时,默认使用 443 端口)。

        其区别主要就在于连接的性质和通信方式。

        WebSocket是一种双向通信的协议,通过一次握手即可建立持久性的连接,服务器和客户端可以随时发送和接收数据。而HTTP协议是一种请求-响应模式的协议,每次通信都需要发送一条请求并等待服务器的响应。

        WebSocket的实时性更好,延迟更低,并且在服务器和客户端之间提供双向的即时通信能力,适用于需要实时数据传输的场景。

四、常见应用场景

  1. 实时聊天:WebSocket能够提供双向、实时的通信机制,使得实时聊天应用能够快速、高效地发送和接收消息,实现即时通信。
  2. 实时协作:用于实时协作工具,如协同编辑文档、白板绘画、团队任务管理等,团队成员可以实时地在同一页面上进行互动和实时更新。
  3. 实时数据推送:用于实时数据推送场景,如股票行情、新闻快讯、实时天气信息等,服务器可以实时将数据推送给客户端,确保数据的及时性和准确性。
  4. 多人在线游戏:实时的双向通信机制,适用于多人在线游戏应用,使得游戏服务器能够实时地将游戏状态和玩家行为传输给客户端,实现游戏的实时互动。
  5. 在线客服:WebSocket可以用于在线客服和客户支持系统,实现实时的客户沟通和问题解决,提供更好的用户体验,减少等待时间。

五、SpringBoot集成WebSocket

引入依赖

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

1. 原生注解

WebSocketConfig 

package com.cjian.websocket.annotation;import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.config.annotation.EnableWebSocket;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;//开启WebSocket的支持,并把该类注入到spring容器中
@Configuration
@EnableWebSocket
public class WebSocketConfig {@Beanpublic ServerEndpointExporter serverEndpointExporter() {return new ServerEndpointExporter();}}

说明:

这个配置类很简单,通过这个配置 spring boot 才能去扫描后面的关于 websocket 的注解

WsServerEndpoint

package com.cjian.websocket.annotation;import cn.hutool.json.JSONUtil;
import jakarta.websocket.OnClose;
import jakarta.websocket.OnMessage;
import jakarta.websocket.OnOpen;
import jakarta.websocket.Session;
import jakarta.websocket.server.PathParam;
import jakarta.websocket.server.ServerEndpoint;
import org.springframework.stereotype.Component;import java.io.IOException;
import java.util.concurrent.ConcurrentHashMap;@ServerEndpoint(value = "/websocket/{sessionId}")
@Component
public class WsServerEndpoint {private static ConcurrentHashMap<String, WsServerEndpoint> webSocketMap = new ConcurrentHashMap<>();//实例一个session,这个session是websocket的sessionprivate Session session;//新增一个方法用于主动向客户端发送消息public static void sendMessage(String message, String sessionId) {WsServerEndpoint webSocket = webSocketMap.get(sessionId);if (webSocket != null) {try {webSocket.session.getBasicRemote().sendText(message);} catch (IOException e) {e.printStackTrace();}}}/*** 连接成功** @param session*/@OnOpenpublic void onOpen(Session session, @PathParam("sessionId") String sessionId) {this.session = session;webSocketMap.put(sessionId, this);sendMessage("connect success", sessionId);}/*** 连接关闭** @param session*/@OnClosepublic void onClose(Session session, @PathParam("sessionId") String sessionId) throws IOException {webSocketMap.remove(sessionId);session.close();}/*** 接收到消息** @param text*/@OnMessagepublic void onMsg(String text, @PathParam("sessionId") String sessionId) {sendMessage("receive msg from client:" + text, sessionId);}}

说明

这里有几个注解需要注意一下,首先是他们的包都在 **jakarta.websocket **下(我用的jdk22)。并不是 spring 提供的,而 jdk 自带的,下面是他们的具体作用。

  1. @ServerEndpoint:通过这个 spring boot 就可以知道你暴露出去的 ws 应用的路径,有点类似我们经常用的@RequestMapping。比如你的启动端口是8080,而这个注解的值是ws,那我们就可以通过 ws://127.0.0.1:8080/ws 来连接你的应用
  2. @OnOpen:当 websocket 建立连接成功后会触发这个注解修饰的方法,注意它有一个 Session 参数
  3. @OnClose:当 websocket 建立的连接断开后会触发这个注解修饰的方法,注意它有一个 Session 参数
  4. @OnMessage:当客户端发送消息到服务端时,会触发这个注解修改的方法,它有一个 String 入参表明客户端传入的值
  5. @OnError:当 websocket 建立连接时出现异常会触发这个注解修饰的方法,注意它有一个 Session 参数

另外一点就是服务端如何发送消息给客户端,服务端发送消息必须通过上面说的 Session 类,通常是在@OnOpen 方法中,当连接成功后把 session 存入 Map 的 value,key 是与 session 对应的用户标识,当要发送的时候通过 key 获得 session 再发送。

使用postman测试:

2. Spring封装

package com.cjian.websocket.spring;import org.springframework.stereotype.Component;
import org.springframework.web.socket.CloseStatus;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.handler.TextWebSocketHandler;@Component
public class CustomWebsocketHandler extends TextWebSocketHandler {@Overridepublic void afterConnectionEstablished(WebSocketSession session) throws Exception {String name = (String) session.getAttributes().get("name");session.sendMessage(new TextMessage(name + " connection success"));}@Overrideprotected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {session.sendMessage(new TextMessage("receive msg:" + message.getPayload()));}@Overridepublic void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {session.close();}
}

说明

通过继承 TextWebSocketHandler 类并覆盖相应方法,可以对 websocket 的事件进行处理,这里可以同原生注解的那几个注解连起来看

  1. afterConnectionEstablished 方法是在 socket 连接成功后被触发,同原生注解里的 @OnOpen 功能
  2. afterConnectionClosed  方法是在 socket 连接关闭后被触发,同原生注解里的 @OnClose 功能
  3. handleTextMessage 方法是在客户端发送信息时触发,同原生注解里的 @OnMessage 功能
CustomInterceptor
package com.cjian.websocket.spring;import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.http.server.ServletServerHttpRequest;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.WebSocketHandler;
import org.springframework.web.socket.server.support.HttpSessionHandshakeInterceptor;import java.util.Map;@Component
public class CustomInterceptor extends HttpSessionHandshakeInterceptor {/*** 握手前*/@Overridepublic boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, Map<String, Object> attributes) throws Exception {System.out.println("start hand shake");ServletServerHttpRequest httpRequest = (ServletServerHttpRequest) request;String name = httpRequest.getServletRequest().getParameter("name");attributes.put("name", name);return super.beforeHandshake(request, response, wsHandler, attributes);}/*** 握手后*/@Overridepublic void afterHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, Exception exception) {System.out.println("hand shake end");}}

说明

通过实现 HandshakeInterceptor 接口来定义握手拦截器,注意这里与上面 Handler 的事件是不同的,这里是建立握手时的事件,分为握手前与握手后,而  Handler 的事件是在握手成功后的基础上建立 socket 的连接。所以在如果把认证放在这个步骤相对来说最节省服务器资源。它主要有两个方法 beforeHandshake 与 **afterHandshake **,顾名思义一个在握手前触发,一个在握手后触发。

CustomWebSocketConfig
package com.cjian.websocket.spring;import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.config.annotation.EnableWebSocket;
import org.springframework.web.socket.config.annotation.WebSocketConfigurer;
import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry;@Configuration
@EnableWebSocket
public class CustomWebSocketConfig implements WebSocketConfigurer {@Autowiredprivate CustomWebsocketHandler customWebsocketHandler;@Autowiredprivate CustomInterceptor myInterceptor;@Overridepublic void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {registry.addHandler(customWebsocketHandler, "myWS").addInterceptors(myInterceptor).setAllowedOrigins("*");}
}

说明

通过实现 WebSocketConfigurer 类并覆盖相应的方法进行 websocket 的配置。我们主要覆盖 registerWebSocketHandlers 这个方法。通过向 WebSocketHandlerRegistry 设置不同参数来进行配置。其中 **addHandler 方法添加我们上面的写的 ws 的  handler 处理类,第二个参数是你暴露出的 ws 路径。addInterceptors 添加我们写的握手过滤器。setAllowedOrigins("*") **这个是关闭跨域校验,方便本地调试,线上推荐打开。

测试:

参考:https://www.cnblogs.com/kiwifly/p/11729304.html 

相关文章:

websocket的介绍及springBoot集成示例

目录 一、什么是Websocket 二、Websocket特点 三、WebSocket与HTTP的区别 四、常见应用场景 五、SpringBoot集成WebSocket 1. 原生注解 2. Spring封装 一、什么是Websocket WebSocket 是一种在单个 TCP 连接上进行 全双工 通信的协议&#xff0c;它可以让客户端和服务器…...

软件测试-自动化测试

自动化测试 测试人员编写自动化测试脚本&#xff0c;维护并解决自动化脚本问题 自动化的主要目的就是用来进行回归测试 回归测试 常见面试题 ⾃动化测试能够取代人工测试吗&#xff1f; ⾃动化测试不⼀定⽐人工测试更能保障系统的可靠性&#xff0c;⾃动化测试是测试⼈员手…...

Linux 安装TELEPORT堡垒机

一、查看官方文档 堡垒机官网地址&#xff1a;走向成功 - Teleport&#xff0c;高效易用的堡垒机 &#xff08;一&#xff09;官网资源链接 -》Teleport 在线文档 &#xff08;二&#xff09;手动下载安装包 二、压缩包下载和安装 &#xff08;一&#xff09;加压下载的安装…...

【14】即时编译器的中间表达形式

中间表达形式&#xff08;IR&#xff09; 编译器一般被分为前端和后端。 前端会对输入的程序进行词法分析、语法分析和语义分析&#xff0c;然后生成中间表达形式&#xff08;IR&#xff09;&#xff1b;后端对IR进行优化&#xff0c;生成目标代码 不考虑解释执行的话&#xf…...

Mysql(三)---增删查改(基础)

文章目录 前言1.补充1.修改表名1.2.修改列名1.3.修改列类型1.4.增加新列1.5.删除指定列 2.CRUD3.新增(Create)3.1.单行插入3.2.指定列插入3.3.多行插入 4.数据库的约束4.1.约束的分类4.2.NULL约束4.3.Unique约束4.4.Default 默认值约束4.5.PRIMARY KEY&#xff1a;主键约束4.6.…...

Dialog实现原理分析

在 Android 中&#xff0c;对话框&#xff08;Dialog&#xff09;是一种非常常见的用户界面组件&#xff0c;用于向用户提供额外的信息或者请求用户的确认。Android 提供了几种不同类型的对话框&#xff0c;例如简单的消息对话框 (AlertDialog)、进度条对话框 (ProgressDialog)…...

21.1 基于Netty实现聊天

21.1 基于Netty实现聊天 一. 章节概述二. `Netty`介绍三. 阻塞与非阻塞1. 阻塞与非阻塞简介2. BIO同步阻塞3. NIO同步非阻塞4. AIO异步非阻塞IO5. 异步阻塞IO(用的极少)6. 总结四. Netty三种线程模型1. 单线程模型2. 多线程模型3. 主从线程模型五. 构建Netty服务器************…...

尼卡音乐 v1.0.5 — 全新推出的免费音乐听歌软件

尼卡音乐是一款全新推出的免费音乐听歌软件&#xff0c;无需注册登录&#xff0c;打开即拥有全部功能。聚合了六大音源曲库、歌单、排行榜&#xff0c;支持在线试听、无损下载以及高清MV播放。资源全、无广告、更新快&#xff0c;适合寻找高品质音乐体验的用户。 拿走的麻烦评…...

Scratch深潜:解锁递归与分治算法的编程之门

亮眼标题&#xff1a;“Scratch深潜&#xff1a;解锁递归与分治算法的编程之门” 在编程的世界里&#xff0c;递归和分治算法是解决问题的强大工具。Scratch&#xff0c;这款广受儿童和初学者欢迎的图形化编程语言&#xff0c;以其独特的拖拽式编程块&#xff0c;激发了无数年…...

【1.0】vue3的创建

【1.0】vue3的创建 【一】vue3介绍 vue2的所有东西&#xff0c;vue3都兼容 vue3中写js代码由两种&#xff0c;组合式和配置项 配置项api&#xff0c;就是vue2的写法&#xff0c;将数据放进data&#xff0c;方法放进methods等 export default{data(){return {}},methods:…...

刷刷前端手写题

闭包用途 闭包 闭包让你可以在一个内层函数中访问到其外层函数的作用域 防抖 描述 前面所有触发都被取消&#xff0c;最后一次执行&#xff0c;在规定时间之后才会触发&#xff0c;也就是说如果连续快速的触发&#xff0c;用户操作频繁&#xff0c;但只会执行一次 。 常用场…...

论文解读:LONGWRITER: UNLEASHING 10,000+ WORD GENERATION FROM LONG CONTEXT LLMS

摘要 现象&#xff1a;当前的大预言模型可以接受超过100,000个tokens的输入&#xff0c;但是却难以生成超过2000个token的输出。 原因&#xff1a;监督微调过程(SFT)中看到的样本没有足够长的样本。 解决方法&#xff1a; Agent Write&#xff0c;可以将长任务分解为子任务&a…...

一文了解Ansible原理以及常见使用模块

ansible使用手册 1. 简述 Ansible 是一种开源的自动化工具&#xff0c;主要用于配置管理、应用程序部署和任务自动化。 它使用简单的 YAML 语言来定义自动化的任务【playbook】&#xff0c;使得配置和部署变得更加直观和易于管理。 基于SSH协议连接到远程主机来执行指令。 2…...

JavaEE从入门到起飞(九) ~Activiti 工作流

工作流 当一道流程逻辑需要用到多个表单的提交和多个角色的审核共同完成的时候&#xff0c;就可以使用工作流。 工作流一般使用的是第三方技术&#xff0c;也就是说别人帮你创建数据库表和service层、mapper层&#xff0c;你只需要注入工具接口即可使用。 原理&#xff1a;一…...

微服务的保护

一、雪崩问题及解决方案 1.雪崩问题 微服务之间&#xff0c;一个微服务依赖多个其他的微服务。当一个微服务A依赖的一个微服务B出错时&#xff0c;微服务A会被阻塞&#xff0c;但其他不依赖于B的微服务不会受影响。 当有多个微服务依赖于B时&#xff0c;服务器支持的线程和并…...

2024前端面试题-网络篇

1.跨域问题 同源策略&#xff1a;需要协议、域名、端口号相同跨域原因&#xff1a;不符合同源策略便会产生跨域问题解决跨域&#xff1a;JSONP、配置代理、通过CORS解决 2.RPC和HTTP的区别 主要区别是序列化和反序列化&#xff0c;RPC通过二进制高效传输&#xff0c;HTTP是j…...

移情别恋c++ ദ്ദി˶ー̀֊ー́ ) ——6.vector

1.杨辉三角 . - 力扣&#xff08;LeetCode&#xff09; 在「杨辉三角」中&#xff0c;每个数是它左上方和右上方的数的和。 class Solution { public:vector<vector<int>> generate(int numRows) {vector<vector<int>> arr;int i 0;int j 0;for (i…...

设计模式---简单工厂模式

简单工厂模式&#xff08;Simple Factory Pattern&#xff09; 是一种创建型设计模式&#xff0c;它定义了一个工厂类&#xff0c;通过这个工厂类可以创建不同类型的对象。简单工厂模式的主要目的是将对象的创建逻辑集中在一个地方&#xff0c;简化客户端的代码&#xff0c;使得…...

Vue | Vue 中的 refInForde 用法

refInFor&#xff1a;如果你在渲染函数中给多个元素都应用了相同的 ref 名&#xff0c;那么 $refs.myRef 会变成一个数组。 vue中的refInFor属性是Vue框架中用于在循环渲染的元素上设置引用的一种方式。‌ 在Vue中&#xff0c;‌ref属性通常用于给元素或子组件注册引用信息&am…...

【原创】java+swing+mysql房屋租赁管理系统设计与实现

个人主页&#xff1a;程序员杨工 个人简介&#xff1a;从事软件开发多年&#xff0c;前后端均有涉猎&#xff0c;具有丰富的开发经验 博客内容&#xff1a;全栈开发&#xff0c;分享Java、Python、Php、小程序、前后端、数据库经验和实战 文末有本人名片&#xff0c;希望和大家…...

理解 MCP 工作流:使用 Ollama 和 LangChain 构建本地 MCP 客户端

&#x1f31f; 什么是 MCP&#xff1f; 模型控制协议 (MCP) 是一种创新的协议&#xff0c;旨在无缝连接 AI 模型与应用程序。 MCP 是一个开源协议&#xff0c;它标准化了我们的 LLM 应用程序连接所需工具和数据源并与之协作的方式。 可以把它想象成你的 AI 模型 和想要使用它…...

镜像里切换为普通用户

如果你登录远程虚拟机默认就是 root 用户&#xff0c;但你不希望用 root 权限运行 ns-3&#xff08;这是对的&#xff0c;ns3 工具会拒绝 root&#xff09;&#xff0c;你可以按以下方法创建一个 非 root 用户账号 并切换到它运行 ns-3。 一次性解决方案&#xff1a;创建非 roo…...

linux 下常用变更-8

1、删除普通用户 查询用户初始UID和GIDls -l /home/ ###家目录中查看UID cat /etc/group ###此文件查看GID删除用户1.编辑文件 /etc/passwd 找到对应的行&#xff0c;YW343:x:0:0::/home/YW343:/bin/bash 2.将标红的位置修改为用户对应初始UID和GID&#xff1a; YW3…...

零基础设计模式——行为型模式 - 责任链模式

第四部分&#xff1a;行为型模式 - 责任链模式 (Chain of Responsibility Pattern) 欢迎来到行为型模式的学习&#xff01;行为型模式关注对象之间的职责分配、算法封装和对象间的交互。我们将学习的第一个行为型模式是责任链模式。 核心思想&#xff1a;使多个对象都有机会处…...

华硕a豆14 Air香氛版,美学与科技的馨香融合

在快节奏的现代生活中&#xff0c;我们渴望一个能激发创想、愉悦感官的工作与生活伙伴&#xff0c;它不仅是冰冷的科技工具&#xff0c;更能触动我们内心深处的细腻情感。正是在这样的期许下&#xff0c;华硕a豆14 Air香氛版翩然而至&#xff0c;它以一种前所未有的方式&#x…...

20个超级好用的 CSS 动画库

分享 20 个最佳 CSS 动画库。 它们中的大多数将生成纯 CSS 代码&#xff0c;而不需要任何外部库。 1.Animate.css 一个开箱即用型的跨浏览器动画库&#xff0c;可供你在项目中使用。 2.Magic Animations CSS3 一组简单的动画&#xff0c;可以包含在你的网页或应用项目中。 3.An…...

莫兰迪高级灰总结计划简约商务通用PPT模版

莫兰迪高级灰总结计划简约商务通用PPT模版&#xff0c;莫兰迪调色板清新简约工作汇报PPT模版&#xff0c;莫兰迪时尚风极简设计PPT模版&#xff0c;大学生毕业论文答辩PPT模版&#xff0c;莫兰迪配色总结计划简约商务通用PPT模版&#xff0c;莫兰迪商务汇报PPT模版&#xff0c;…...

MacOS下Homebrew国内镜像加速指南(2025最新国内镜像加速)

macos brew国内镜像加速方法 brew install 加速formula.jws.json下载慢加速 &#x1f37a; 最新版brew安装慢到怀疑人生&#xff1f;别怕&#xff0c;教你轻松起飞&#xff01; 最近Homebrew更新至最新版&#xff0c;每次执行 brew 命令时都会自动从官方地址 https://formulae.…...

Linux系统部署KES

1、安装准备 1.版本说明V008R006C009B0014 V008&#xff1a;是version产品的大版本。 R006&#xff1a;是release产品特性版本。 C009&#xff1a;是通用版 B0014&#xff1a;是build开发过程中的构建版本2.硬件要求 #安全版和企业版 内存&#xff1a;1GB 以上 硬盘&#xf…...

【Linux手册】探秘系统世界:从用户交互到硬件底层的全链路工作之旅

目录 前言 操作系统与驱动程序 是什么&#xff0c;为什么 怎么做 system call 用户操作接口 总结 前言 日常生活中&#xff0c;我们在使用电子设备时&#xff0c;我们所输入执行的每一条指令最终大多都会作用到硬件上&#xff0c;比如下载一款软件最终会下载到硬盘上&am…...