双向通信之Websocket
介绍
Websocket是一种在单个TCP连接上进行全双工通信的协议。与传统的HTTP协议不同,websocket允许客户端与服务器之间的双向通信,可以在同一条连接上进行多次消息的快速传递。我之前在做一个线上刷题网站的时候,需要设计一个社区讨论模块,当有用户评论了我的动态内容或者回复了我的评论的时候我需要被通知,那么这边我就使用了websocket来实现消息回复的实时通知功能。
Websocket协议
原理
它的工作原理大致分为以下这么几个部分:
1.建立连接:客户端在初次加载的时候通过HTTP向服务端发起建立websocket连接的请求,服务端接收到之后同意连接,那么服务端就会将HTTP连接升级到websocket连接。这里分为两步:
握手请求:客户端向服务端发送的HTTP请求包含关键性头部:Connection:upgrade,upgrade:websocket,代表要求升级到websocket协议;sec-websocket-key是基于base64编码生成的校验值,用于服务端对请求进行校验。
握手响应:服务端在接收到请求之后,校验通过会生成101switching code返回,代表升级协议成功,同时还有sec-websocket-Accept,代表请求校验的合法性。
2.数据传输:建立连接成功之后双方就可以发送数据帧了,数据帧的关键性字段包括有:FIN代表这是最后一帧,Opcode代表数据传输的格式(文本帧/二进制帧等),负载数据负载长度等等。
3.关闭连接:客户端和服务端任何一方都可以关闭连接,也可以是网络中断关闭连接。
4.心跳机制:为了确保双方通信的活跃性,客户端或者服务端可以随时向对方发送ping帧,对方接收到之后返回一个pong帧。
5.安全性:websocket可以运行在TLS协议上确保传输的安全性,比如大家熟知的HTTPS就是HTTP+TLS。
业务代码实现
这里我们将给出我们项目中使用websocket实现的消息回复实时通知的部分代码。
首先我们需要做一些配置,我们要求前端请求中有一个"erp"项用于存放用户的openid,方便我们用于作唯一标识来识别不同的用户。
@Component
public class WebSocketServerConfig extends ServerEndpointConfig.Configurator {@Overridepublic boolean checkOrigin(String originHeaderValue) {return true;}@Overridepublic void modifyHandshake(ServerEndpointConfig sec, HandshakeRequest request, HandshakeResponse response) {Map<String, List<String>> parameterMap = request.getParameterMap();List<String> erpList = parameterMap.get("erp");if(!CollectionUtils.isEmpty(erpList)){sec.getUserProperties().put("erp", erpList.get(0));}}}
接着就是我们自定义websocket类的编写,在这边我们将实现消息的推送、异常处理、客户端的连接与关闭的逻辑。首先是连接成功与关闭的逻辑:
/*** 连接建立成功调用的方法*/@OnOpenpublic void onOpen(Session session, EndpointConfig conf) throws IOException {//获取用户信息try {Map<String, Object> userProperties = conf.getUserProperties();String erp = (String) userProperties.get("erp");this.erp = erp;this.session = session;if (clients.containsKey(this.erp)) {clients.get(this.erp).session.close();clients.remove(this.erp);onlineCount.decrementAndGet();}clients.put(this.erp, this);onlineCount.incrementAndGet();log.info("有新连接加入:{},当前在线人数为:{}", erp, onlineCount.get());sendMessage("连接成功", this.session);if(offlineMessages.containsKey(this.erp)){ConcurrentLinkedQueue<String> messages = offlineMessages.get(this.erp);while (!messages.isEmpty()){sendMessage(messages.poll(),this.session);}}} catch (Exception e) {log.error("建立链接错误{}", e.getMessage(), e);}}/*** 连接关闭调用的方法*/@OnClosepublic void onClose() {try {if (clients.containsKey(erp)) {clients.get(erp).session.close();clients.remove(erp);onlineCount.decrementAndGet();offlineMessages.computeIfAbsent(erp, k -> new ConcurrentLinkedQueue<>()).add("你不在的时候,南师很想你哦!!!");}log.info("有一连接关闭:{},当前在线人数为:{}", this.erp, onlineCount.get());} catch (Exception e) {log.error("连接关闭错误,错误原因{}", e.getMessage(), e);}}
在这边我们维护了一个map缓存存放某个用户断开连接期间其他用户发送的消息,等到用户再次上线时推送,这边我们目前是采用的缓存维护的方式,后续会做一个优化,考虑到如果该服务挂掉,那么缓存里的数据就会丢失,所以我们可以在这边对数据做一个持久化比如存储到数据库,服务挂掉之后重启的时候去表中读取未推送的数据加载到缓存中,这是需要优化的一个点;当然也可以考虑将数据存到redis里面配合redis的数据持久化机制可以保证数据不会丢失,但是需要考虑redis宕机的问题,这些不是本文讨论的重点,感兴趣的小伙伴可以根据可能出现的问题进行下一步思考。
然后是发送消息的逻辑,包括用户在线离线发送和群发消息的逻辑:
/*** 指定发送消息*/public void sendMessage(String message, Session session) {if(session!=null){log.info("服务端给客户端[{}]发送消息{}", this.erp, message);try {session.getBasicRemote().sendText(message);} catch (IOException e) {log.error("{}发送消息发生异常,异常原因{}", this.erp, message);}}}public void sendMessage(String message, String toId) {offlineMessages.computeIfAbsent(toId, k -> new ConcurrentLinkedQueue<>()).add(message);}/*** 群发消息*/public void sendMessage(String message) {for (Map.Entry<String, ChickenSocket> sessionEntry : clients.entrySet()) {String erp = sessionEntry.getKey();ChickenSocket socket = sessionEntry.getValue();Session session = socket.session;log.info("服务端给客户端[{}]发送消息{}", erp, message);try {session.getBasicRemote().sendText(message);} catch (IOException e) {log.error("{}发送消息发生异常,异常原因{}", this.erp, message);}}}
总结
在这里我们探讨了websocket的工作原理以及它在我们项目中的具体应用。除了消息回复的实时通知,它的应用也是非常广泛,比如说实时更新(股票行情,游戏数据更新),在线协作等等。相较于HTTP协议,websocket的通信模式是双向通信模式,而HTTP是请求响应模式,并且HTTP每次请求都会带上大量的请求头,websocket在建立连接之后只传输很少的头部信息。所以在不同的场景下我们考虑使用不同的协议,简单场景下HTTP已经足够,如果是双方消息通知或者实时推送的话可以考虑websocket协议。最后如果大家有什么想法,欢迎讨论。
相关文章:
双向通信之Websocket
介绍 Websocket是一种在单个TCP连接上进行全双工通信的协议。与传统的HTTP协议不同,websocket允许客户端与服务器之间的双向通信,可以在同一条连接上进行多次消息的快速传递。我之前在做一个线上刷题网站的时候,需要设计一个社区讨论模块&am…...

git学习使用碰到的问题1
本来在B站上看到的关于stash的使用时视频末尾讲到git stash drop 编号 会删除暂存记录 确实也是这么回事,但是末尾说到git stash pop 编号时up主说在恢复工作进度的时候我们可以直接删除掉这个工作记录可以直接使用 git stash pop stash{0} 使用完以后却出现了如上图…...
JavaScript初级——Math
一、Math 和其他的对象不同,它不是一个构造函数。它属于一个工具类,不用创建对象,里边封装了数学运算相关的属性和方法。 比如: Math.PI 表示圆周率。 二、Math.abs() —— 可以用来计算一个数的绝对值。 三…...

ffmpeg的基础命令
文章目录 ffmpeg/ffplay/ffprobe区别ffmpeg 的作用ffplay的作用ffprobe的作用 ffmpeg使用概述功能概述转码过程简单使用FFMPEG -i常用的 -i例子 ff***工具之间共享的选项ffmpeg主要选项ffmpeg提取音视频数据ffmpeg命令修改原有的视频格式ffmpeg命令裁剪和合并视频拼接视频的方式…...
二建机电工程实务试题内附答案
1.下列有色金属材料中,不属于铜合金的是()。 A.紫铜 B.青铜 C.黄铜 D.白铜【答案】A 2.用于完成介质间热量交换的换热设备是()。 A.分离器 B.反应器 C.冷凝器 D.分解锅【答案】C 3.工程测量的核心是()。 A.测量精度 B.设计要求 C.减少误差累积 D.检核【答案】D 4.吊…...
Redis的热key以及Big(大)key是什么?如何解决Redis的热key以及Big(大)key问题?
一、先讲讲什么是redis的热key问题 在Redis中,我们把访问频率高的Key,称为热Key。比如突然有几十万的请求去访问redis中某个特定的Key,那么这样会造成redis服务器短时间流量过于集中,很可能导致redis的服务器宕机。那么接下来对这…...
django学习入门系列之第九点《MySQL命令介绍一》
文章目录 MySQL命令数据库的管理(文件夹)查看现在已有的数据库(文件夹)创建数据库(文件夹)删除数据库(文件夹)进入数据库(文件夹)查看文件夹下所有的数据表&a…...
Mysql面试一
目录 一、事务的四大特性(ACID): 脏读 不可重复读 幻读 隔离性与隔离级别 数据库的三大范式 第一范式。确保数据表中的每个字段都是不可分割的最小单位,即原子性。这意味着表中的每一列都应代表一个独立的数据单元ÿ…...

模型优化之剪枝
文章目录 什么是神经网络剪枝剪枝的好处不同粒度的剪枝剪枝的分类非结构化剪枝结构化剪枝 哪些层的参数更容易被剪掉剪枝效果 什么是神经网络剪枝 神经网络剪枝 在训练期间删除连接密集张量将变得稀疏(用零填充)可以通过结构化块( n m nm nm&…...

JVM的组成
JVM 运行在操作系统之上 java二进制字节码文件的运行环境 JVM的组成部分 java代码在编写完成后编译成字节码文件通过类加载器 来到运行数据区,主要作用是加载字节码到内存 包含 方法区/元空间 堆 程序计数器,虚拟机栈,本地方法栈等等 随后来到执行引擎,主要作用是翻译字…...
快速上手 iOS Protocol Buffer
快速上手 iOS Protocol Buffer | 来自缤纷多彩的灰 本文主要介绍在 iOS 开发中如何快速上手使用 Protobuf。更多关于 Protobuf 的介绍和相关的功能 api,读者可自行查阅官网。 Protocol Buffer(简称 Protobuf)是一种由Google开发的语言中立、…...
每天一个数据分析题(四百八十)- 线性回归建模
关于线性回归建模,线性回归模型假设说法不正确的是? A. 因变量和自变量要有因果关系 B. 残差均值为0 C. 残差服从正态分布 D. 自变量不存在共线性 数据分析认证考试介绍:点击进入 题目来源于CDA模拟题库 点击此处获取答案 数据分析专…...

电动汽车和混动汽车DC-DC转换器的创新设计与测试方法
汽车 DC-DC 转换器市场规模将达到187亿美元,年复合增长率为10%。 DC-DC 转换器是汽车的重要组成部分,它可以通过电压转换为各种车载系统供电,例如日益复杂的车载信息娱乐系统、使用驾驶辅助系统(ADAS)实现的增强安全功…...

OriginPro快速上手指南:数据可视化与分析的利器
目录 OriginLab - Origin and OriginPro - Data Analysis and Graphing Softwarehttps://www.originlab.com/编辑 一、安装与界面概览 安装 界面概览 二、基础操作 数据输入 创建图表 三、高级功能 数据分析 自动化与脚本 Origin 提供了几个小工具 四、技巧与提示…...

缓存学习
缓存基本概念 概念 对于缓存,最普遍的理解是能让打开某些页面速度更快的工具。从技术角度来看,其本质上是因为缓存是基于内存建立的,而内存的读写速度相比之于硬盘快了xx倍,因此用内存来代替硬盘作为读写的介质当然能大大提高访…...

亚世光电:消费电子年度表演
机圈风云再起,消费电子乘风而起? 今天我们来聊——亚世光电 最近,华为mate60突然降价,被大家怀疑是为新品上市做准备,算算时间,下半年的消费电子大战也即将拉开帷幕,而亚世光电所在的光电显示领…...

AI 工程应用 建筑表面检测及修复
文章目录 1 项目概述(必写):2 技术方案与实施步骤2.1 模型选择(必写):2.2 数据的构建:2.3 功能整合(进阶): 3 实施步骤:3.1 环境搭建(…...

Qt-Qt中的小事项(7)
目录 命名风格 快捷键 查询文档 坐标系 代码理解 move 命名风格 这个也是老生常谈的问题了,入乡随俗就好啦 快捷键 这里是一些常用的快捷键,用多了自然就熟悉了 • 注释:ctrl/ • 运行:ctrlR • 编译:ctrlB …...
Android MediaRecorder 视频录制及报错解决
目录 一、start failed: -19 二、使用MediaRecorder录制视频 2.1 申请权限 2.2 布局文件 2.3 MediaRecordActivity 2.4 运行结果 三、拓展 3.1 录制视频模糊(解决) 3.2 阿里云OSS上传文件 3.2.1 权限(刚需) 3.2.2 安装SDK 3.2.3 使用 相关链接 一、start failed…...

HarmonyOS应用程序访问控制探究
关于作者 白晓明 宁夏图尔科技有限公司董事长兼CEO、坚果派联合创始人 华为HDE、润和软件HiHope社区专家、鸿蒙KOL、仓颉KOL 华为开发者学堂/51CTO学堂/CSDN学堂认证讲师 开放原子开源基金会2023开源贡献之星 一、引言 随着信息技术的飞速发展,移动应用程序已经成为…...
synchronized 学习
学习源: https://www.bilibili.com/video/BV1aJ411V763?spm_id_from333.788.videopod.episodes&vd_source32e1c41a9370911ab06d12fbc36c4ebc 1.应用场景 不超卖,也要考虑性能问题(场景) 2.常见面试问题: sync出…...
FFmpeg 低延迟同屏方案
引言 在实时互动需求激增的当下,无论是在线教育中的师生同屏演示、远程办公的屏幕共享协作,还是游戏直播的画面实时传输,低延迟同屏已成为保障用户体验的核心指标。FFmpeg 作为一款功能强大的多媒体框架,凭借其灵活的编解码、数据…...
【Linux】C语言执行shell指令
在C语言中执行Shell指令 在C语言中,有几种方法可以执行Shell指令: 1. 使用system()函数 这是最简单的方法,包含在stdlib.h头文件中: #include <stdlib.h>int main() {system("ls -l"); // 执行ls -l命令retu…...
系统设计 --- MongoDB亿级数据查询优化策略
系统设计 --- MongoDB亿级数据查询分表策略 背景Solution --- 分表 背景 使用audit log实现Audi Trail功能 Audit Trail范围: 六个月数据量: 每秒5-7条audi log,共计7千万 – 1亿条数据需要实现全文检索按照时间倒序因为license问题,不能使用ELK只能使用…...

【CSS position 属性】static、relative、fixed、absolute 、sticky详细介绍,多层嵌套定位示例
文章目录 ★ position 的五种类型及基本用法 ★ 一、position 属性概述 二、position 的五种类型详解(初学者版) 1. static(默认值) 2. relative(相对定位) 3. absolute(绝对定位) 4. fixed(固定定位) 5. sticky(粘性定位) 三、定位元素的层级关系(z-i…...

学习STC51单片机31(芯片为STC89C52RCRC)OLED显示屏1
每日一言 生活的美好,总是藏在那些你咬牙坚持的日子里。 硬件:OLED 以后要用到OLED的时候找到这个文件 OLED的设备地址 SSD1306"SSD" 是品牌缩写,"1306" 是产品编号。 驱动 OLED 屏幕的 IIC 总线数据传输格式 示意图 …...
论文解读:交大港大上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化学习框架(一)
宇树机器人多姿态起立控制强化学习框架论文解析 论文解读:交大&港大&上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化学习框架(一) 论文解读:交大&港大&上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化…...
Matlab | matlab常用命令总结
常用命令 一、 基础操作与环境二、 矩阵与数组操作(核心)三、 绘图与可视化四、 编程与控制流五、 符号计算 (Symbolic Math Toolbox)六、 文件与数据 I/O七、 常用函数类别重要提示这是一份 MATLAB 常用命令和功能的总结,涵盖了基础操作、矩阵运算、绘图、编程和文件处理等…...
Python如何给视频添加音频和字幕
在Python中,给视频添加音频和字幕可以使用电影文件处理库MoviePy和字幕处理库Subtitles。下面将详细介绍如何使用这些库来实现视频的音频和字幕添加,包括必要的代码示例和详细解释。 环境准备 在开始之前,需要安装以下Python库:…...
浅谈不同二分算法的查找情况
二分算法原理比较简单,但是实际的算法模板却有很多,这一切都源于二分查找问题中的复杂情况和二分算法的边界处理,以下是博主对一些二分算法查找的情况分析。 需要说明的是,以下二分算法都是基于有序序列为升序有序的情况…...