SpringBoot集成WebSocket实现客户端与服务端长连接通信

2023-10-29

场景:
1、WebSocket协议是用于前后端长连接交互的技术,此技术多用于交互不断开的场景。特点是连接不间断、更轻量,只有在关闭浏览器窗口、或者关闭浏览器、或主动close,当前会话对象才会关闭。
2、相较于 Http/Https 通信只能由客户端主动发起请求,而 Socket 通信不仅能由客户端主动发起请求、服务端也可能主动给客户端推送消息

这里只是简单的记录一下使用方式

一、服务端

1、导入 websocket 依赖

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

2、配置 WebSocket 通信协议标准(服务端点导出)对象

    @Bean
    public ServerEndpointExporter serverEndpointExporter() {
        return new ServerEndpointExporter();
    }

说明:
如果没有配置 WebSocket 通信协议标准对象,可能会导致如下错误:

错误一:
VM105:1 WebSocket connection to 'ws://xxx:7002' failed: Error during WebSocket handshake: Unexpected response code: 404

错误二:
This request has been blocked; this endpoint must be available over WSS.

错误三:
VM78:1 WebSocket connection to 'wss://xxx:7002' failed: Error in connection establishment: net::ERR_SSL_PROTOCOL_ERROR

错误四(没有携带token或密钥):
VM78:1 WebSocket connection to 'wss://xxx:7002' failed: Error in connection establishment: net::ERR_SSL_PROTOCOL_ERROR

3、服务端的四个注解方法,对应触发事件

@OnOpen:连接成功交互初始化
@OnMessage:消息事件
@OnClose:关闭事件
@OnError:异常事件

4、websocket 事件服务类,可以理解为Restful Api的映射类(controller)

@Slf4j
@Component
@ServerEndpoint("/websocket/msg/{userId}")
public class WsMessageService {

    //与某个客户端的连接会话,通过此会话对象给客户端发送数据
    private Session session;

    //concurrent包的线程安全Set,用来存放每个客户端对应的WebSocket对象。
    //注:泛型是当前类名
    //private static Set<WsMessageService> webSockets = new CopyOnWriteArraySet<>();
    private static Map<String, WsMessageService> webSocketsBeanMap = new ConcurrentHashMap<>();

    //用来保存在线连接数
    //private static Map<String, Session> sessionPool = new HashMap<>();

    //每次连接都是一个新的会话对象,线程安全的
    String userId;


    @OnOpen
    public void onOpen(Session session, @PathParam(value = "userId") String userId) {
        this.session = session;
        this.userId = userId;
        webSocketsBeanMap.put(userId, this);
        log.info("OnOpen连接成功,userId:{},当前在线人数:{}", userId, this.getOnLineCount());
    }

    @OnMessage
    public void onMessage(String message) throws IOException {
        Session session = webSocketsBeanMap.get(this.userId).session;
        if (ObjectUtil.isNull(session) || !session.isOpen()) {
            return;
        }
        log.info("收到客户端的消息:" + message);
        this.session.getBasicRemote().sendText(String.valueOf(this.getOnLineCount()));
    }

    @OnClose
    public void onClose() throws IOException {
        log.info("会话关闭,关闭会话的用户Id为:{}", this.userId);
        webSocketsBeanMap.remove(this.userId);
        log.info("当前在线人数:{}", this.getOnLineCount());
    }

    @OnError
    public void onError(Session session, Throwable error) {
        log.error("连接错误:" + error.getMessage());
        error.printStackTrace();
    }


    /**
     * <p>返回在线人数</p>
     *
     * @author hkl
     * @date 2023/2/16
     */
    private int getOnLineCount() {
        return webSocketsBeanMap.size();
    }

}

 到这里服务端demo已经完成,可以使用浏览器、HTML页面、Apipost测试

二、测试验证

连接语法:ws://IP地址:端口号

1、使用 Apipost 工具测试

【1】下载安装 Apipost

【2】输入访问地址、连接、发送消息,如下

2、用浏览器测试
第1步:var ws = new WebSocket("ws://localhost:7000/mpj/websocket/1");
第2步:console.log("连接状态:", ws.readyState);

连接状态说明:
0:CONNECTING,表示正在连接。
1:OPEN,表示连接成功,可以通信了。
2:CLOSING,表示连接正在关闭。
3:CLOSED,表示连接已经关闭,或者打开连接失败

第3步:ws.send("hello"); 

示例如下:

 服务端收到消息:

3、使用 html 页面编写js脚本测试

<!DOCTYPE html>
<html lang="zh-cn">
<head>
    <meta charset="UTF-8">
    <meta name="viewport"content="width=device-width, initial-scale=1.0">
    <title>WebSocket测试</title>
    <script>
        function initWebSocket(wsUri) {
            var websocket = new WebSocket(wsUri);
            websocket.onopen = function(evt) {
                console.log('连接建立中... '+wsUri);
            };
            websocket.onclose = function(evt) {
                console.log('连接关闭中...', evt);
            };
            websocket.onmessage = function(evt) {
                console.log('收到来自服务端的消息:', evt.data);
            };
            websocket.onerror = function(evt) {
                console.log('发生错误...', evt);
            };
            return websocket;
        }
    
        //在此配置 websocket 的地址
        var websocket = initWebSocket("ws://localhost:6000/mpj/websocket/msg/1");
        var msg, i = 0;
        var loop = setInterval(function(){
            msg = "Hello " +(i++);
            if(websocket.readyState == WebSocket.OPEN) {
                websocket.send(msg);
                console.log('已发送消息:' +msg);
            } else{
                clearInterval(loop);
                console.log('连接已关闭,拜拜~');
            }
        }, 3000);
    </script>
</head>
<body>请按 F12 打开控制台查看消息
</body>
</html>

运行如下:

 

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

SpringBoot集成WebSocket实现客户端与服务端长连接通信 的相关文章

随机推荐

  • tftp的配置

    首先配置tftp 配置过程如下 首先需要安装tftpd的相关软件包 sudo apt get install xinetd tftpd tftp 设置xinetd的tftp服务 具体为在 etc xinetd d 目录下创建一个tftp文件
  • Angular使用Promise解决多个异步回调问题

    Promise的基本用法 var p1 new Promise resolve reject gt setTimeout resolve 1000 done p1 then data gt console log data done ang
  • 配置文件jdk和hadoop和scala和spark

    bashrc profile java验证java version export JAVA HOME usr lib jvm java export JRE HOME JAVA HOME jre export CLASSPATH JAVA
  • rsync常见问题及解决办法(亲测)

    错误一 password file must not be other accessible continuing without password file Password rsync客户端路径是否写错 权限设置不对 需要再次输入密码
  • python数据结构与算法篇:排序

    1 冒泡排序 英语 Bubble Sort 它重复地遍历要排序的数列 一次比较两个元素 如果他们的顺序错误就把他们交换过来 遍历数列的工作是重复地进行直到没有再需要交换 也就是说该数列已经排序完成 这个算法的名字由来是因为越小的元素会经由交
  • Linux下压缩文件夹命令

    tar zcvf 打包后生成的文件名全路径 要打包的目录 例子 把 xahot文件夹打包后生成一个 home xahot tar gz的文件 tar zcvf home xahot tar gz xahot zip 压缩方法 压缩当前的文件
  • 【ISO】Windows10系统ISO镜像怎么从微软官网下载?

    要自己安装正版系统 第一步就是要下载到正确的系统镜像 下载的方法很多 可以通过搜索 网盘 网站或者论坛等下载 但那都不是最正宗 最纯粹的的 通过这些渠道下载 偶尔 难免也会遇到些心术不正的人给你夹带点私货 从微软官网下载Windows10系
  • Spring多次request.getReader()解决方法

    Spring多次request getReader 解决方法 ServletRequest的getReader和getInputStream只能调用一次 开发中遇到一个需求 对http请求进行打点 其中有个字段是请求body 本来想的是写一
  • 《面试准备》c/c++ 数组实现循环queue

    代码 include
  • 正则表达式“\\s+“ 匹配任意空白字符

    正则表达式中 s匹配任何空白字符 包括空格 制表符 换页符等等 等价于 f n r t v f gt 匹配一个换页 n gt 匹配一个换行符 r gt 匹配一个回车符 t gt 匹配一个制表符 v gt 匹配一个垂直制表符 而 s 则表示匹
  • 算法笔记——回溯

    算法笔记 回溯 回溯法实际上就是把问题的解空间转化成了图或者树的结构表示 然后使用深度优先搜索策略进行遍历 如果遍历的过程中发现已不满足求解条件时 就 回溯 即回退 尝试别的路径 思想 回溯法从根结点出发 按照深度优先策略遍历解空间树 搜索
  • 纳米智能机器—纳米多功能检测

    摘要 病毒是自然界中分布最广 个体数量最多的生命形式 同时它也是许多致死性疾病的罪魁祸首 历史上各种传染性病毒如流感病毒 天花 埃博拉病毒的肆虐给人类带来了巨大的灾难 动物病毒和植物病毒感染造成畜牧业和农业的巨额经济损失 另一方面 病毒具备
  • SIGIR 2021 DCSpell一个代价比较小的预训练文本纠错的模型

    文本纠错概述 文本纠错任务 指的是识别输入文本中出现的拼写错别字及其位置信息 并给出正确的修改建议的任务 文本纠错是自然语言处理领域一项非常重要的任务 在搜索引擎 语音识别 教育等领域有广泛的应用 能够显著地提高各种场景下语义的准确性 比如
  • Yolo置信度

    Yolo置信度 置信度是每个bounding box输出的其中一个重要参数 作者对他的作用定义有两重 一重是 代表当前box是否有对象的概率Pr Object 注意 是对象 不是某个类别的对象 也就是说它用来说明当前box内只是个背景 ba
  • 1、在VMware上如何创建虚拟机以及安装linux操作系统 2、修改主机名为server.local 3、将虚拟机的网络连接模式分别调换成仅主机模式、nat模式、桥接模式并获取ip地址使用ssh通过

    一 在VMware上如何创建虚拟机以及安装linux操作系统 创建虚拟机 1 点击创建新的虚拟机 2 点击自定义 点击下一步 3 兼容性确认好 点击下一步 4 选择稍后安装操作系统 点击下一步 5 选择linux 下一步 6 选择Linux
  • 佳能打印机复印身份证的双面到A4纸上的方法

    1 选择其他功能 页面合并 2 选择来源纸张大小 身份证可以选择A5R大小的 3 选择打印纸张大小 默认A4 4 完成设置 按那个平常的复印将进行扫描 画面上会显示继续扫面R2 然后将身份证翻转放到原来的地方 然后再按扫描 5 最后按界面上
  • centOS7 中安装可视化图形界面

    centOS7 中安装可视化图形界面 一 检查 yum是否可用 输入 yum list 如果出现以下情况说明不可用 二 下载可视化图形界面 2 1 安装 x Windows System 输入 yum groupinstall X Wind
  • html+写入数据库+JDBC更改数据库

    1 HTML部分 2 CSS部分 Login div div div div class input box div div
  • starter-canal 下载并打成依赖放入maven本地仓库

    https github com chenqian56131 spring boot starter canal 下载代码 1 下载完成进入项目根目录starter canal 中 命令行如下 mvn install 2 等待打包完成 ta
  • SpringBoot集成WebSocket实现客户端与服务端长连接通信

    场景 1 WebSocket协议是用于前后端长连接交互的技术 此技术多用于交互不断开的场景 特点是连接不间断 更轻量 只有在关闭浏览器窗口 或者关闭浏览器 或主动close 当前会话对象才会关闭 2 相较于 Http Https 通信只能由