Websocket原理和实践

一、概述

1.websocket是什么?

WebSocket是一种在单个TCP连接上进行全双工通信的协议。WebSocket使得客户端和服务器之间的数据交换变得更加简单,允许服务端主动向客户端推送数据。在WebSocket API中,浏览器和服务器只需要完成一次握手,两者之间就直接可以创建持久性的连接,并进行双向数据传输。

WebSocket与HTTP协议不同,它使用了独立的端口,并且在建立连接后,不需要在每次数据传输时重新建立连接。这使得它特别适合于实时应用程序,例如聊天,在线游戏和股票交易等,这些应用程序需要高速,双向的数据传输。

WebSocket协议是HTML5标准的一部分,因此它可以在现代浏览器中使用。WebSocket API可以在JavaScript中使用,这样就可以在网页上直接使用WebSocket进行通信。

2.websocket和HTTP对比

WebSocket是一种与HTTP不同的协议。两者都位于OSI模型的应用层,并且都依赖于传输层的TCP协议。 虽然它们不同,但是RFC 6455中规定:it is designed to work over HTTP ports 80 and 443 as well as to support HTTP proxies and intermediaries(WebSocket通过HTTP端口80和443进行工作,并支持HTTP代理和中介),从而使其与HTTP协议兼容。 为了实现兼容性,WebSocket握手使用HTTP Upgrade头[1]从HTTP协议更改为WebSocket协议。

其具体的区别如下:

  1. 通信方式不同: HTTP协议是一种请求-响应协议,客户端发送请求给服务器,服务器返回响应。而WebSocket协议是一种全双工协议,客户端和服务器都可以主动发送消息。
  2. 链接状态不同: HTTP协议是无状态的,每次请求都是独立的。而WebSocket协议是有状态的,建立了连接之后,客户端和服务器之间可以维持长连接。
  3. 数据传输不同: HTTP协议是基于文本的,而WebSocket协议是基于二进制的。
  4. 延迟不同: HTTP协议每次请求都需要建立连接,等待响应,传输数据,释放连接,这整个过程都需要一些时间。而WebSocket协议只需要建立一次连接,之后就可以高效地进行数据传输,所以延迟更小。

3.websocket的优势和劣势

  1. **较少的控制开销。**在连接建立后,服务器和客户端之间交换数据时,用于协议控制的数据包头部相对较小。在不包含扩展的情况下,对于服务器到客户端的内容,此头部大小只有2至10字节(和数据包长度有关);对于客户端到服务器的内容,此头部还需要加上额外的4字节的掩码。相对于HTTP请求每次都要携带完整的头部,此项开销显著减少了。
  2. **更强的实时性。**由于协议是全双工的,所以服务器可以随时主动给客户端下发数据。相对于HTTP请求需要等待客户端发起请求服务端才能响应,延迟明显更少;即使是和Comet等类似的长轮询比较,其也能在短时间内更多次地传递数据。
  3. **保持连接状态。**与HTTP不同的是,Websocket需要先建立连接,这就使得其成为一种有状态的协议,之后通信时可以省略部分状态信息。而HTTP请求可能需要在每个请求都携带状态信息(如身份认证等)。
  4. **更好的二进制支持。**Websocket定义了二进制帧,相对HTTP,可以更轻松地处理二进制内容。
  5. **可以支持扩展。**Websocket定义了扩展,用户可以扩展协议、实现部分自定义的子协议。如部分浏览器支持压缩等。
  6. **更好的压缩效果。**相对于HTTP压缩,Websocket在适当的扩展支持下,可以沿用之前内容的上下文,在传递类似的数据时,可以显著地提高压缩率。

4.websocket应用场景

  1. 在线聊天:实现实时的文本聊天功能。
  2. 直播和视频会议:实现实时的音频和视频传输。
  3. 游戏:实现实时的游戏状态同步和控制。
  4. 实时监控和控制:实现实时的硬件监控和控制。
  5. 数据可视化:实现实时的数据可视化和分析。
  6. 在线协作:实现实时的文档协作和编辑。
  7. 智能家居:实现实时的智能家居控制。
  8. 推送消息:实现实时的推送消息功能

这些场景中,WebSocket的实时通信特性使得WebSocket成为了一种理想的选择。

利用websocket处理在线聊天业务的常见流程:

img

二、原理

1.WebSocket通信原理和机制

HTTP通信方式是请求-响应的单工通信,他的通信模式是一问一答式的,如果需要服务端主动发送消息给客户端,他是做不到的。

Websocket的通信方式是全双工模式,无论客户端还是服务端,都能够自主发起通信。但是WebSocket 是独立的、建立在TCP上的协议。Websocket 通过 HTTP/1.1 协议的101状态码进行握手。为了建立Websocket连接,需要通过浏览器发出请求,之后服务器进行回应,这个过程通常称为“握手”(Handshaking)。握手是通过HTTP协议完成的,但是一旦建立连接后,数据传输将使用WebSocket协议。

img

WebSocket通信的流程如下:

  1. 客户端发送一个HTTP请求,请求的目的是为了要建立一个WebSocket连接。
  2. 服务器收到请求后,给出一个HTTP响应,并升级连接到WebSocket协议。
  3. 客户端和服务器之间建立一个WebSocket连接。
  4. 客户端和服务器之间可以进行双向通信,发送文本和二进制数据。
  5. 当客户端或服务器关闭连接时,WebSocket连接也会关闭。

与 HTTP 通信不同的是,WebSocket 通信是基于TCP的,所以它是一个持久连接。它允许服务器主动发送信息给客户端,而不是等待客户端的请求。这使得 WebSocket 通信成为了实现实时应用的理想选择。

建立了websocket连接,请求的URL会以ws://xx开始,在请求头中会有upgrade:websocket标志,说明该请求是websocket请求。

image-20230817164249524

后续客户端和服务器的消息通信会在同一个回话中展示。

image-20230817164304308

2.Java Websocket API介绍

与HTTP不同,websocket的通信具有生命周期,此生命周期由websocket协议本身支撑,具体实现websocket的语言都需要支持。

  1. 建立连接事件:此事件发生在端点上建立新连接时并且在任何其他事件发生之前

  2. 发送消息事件:此事件接收WebSocket对话中另一端发送的消息。它可以发生在WebSocket端点接收了打开事件之后且在接收关闭事件关闭连接之前的任意时刻

  3. 出现错误事件:此事件在WebSocket连接或者端点发生错误时产生

  4. 连接关闭事件:此事件表示WebSocket端点的连接或者端点目前正在部分的关闭,它可以由参与连接的任意一个端点发出

    img

针对Java来说,websocket的事件都会有对应的方法处理,其主要通过编程式端点服务来处理:

  • @OnOpen:处理建立连接的事件;
	@OnOpenpublic void init(Session session, EndpointConfig config) {}
  • @OnMessage:处理建立连接后收发消息的事件;
	@OnMessagepublic void handleTextMessage(String textMessage) {}
-----------@OnMessagepublic void handleBinaryMessage(byte[] messageData, Session session) {}
  • @OnError:处理消息时候发生错误的处理;
  • @OnClose:处理连接关闭的事件;

三、实践

1.Springboot集成Websocket

通过Springboot集成Websocket有两种实现,分别是基于注解的实现和实现接口的方式,下面分别展开:

1.1.基于注解

添加pom依赖

在pom配置文件中引入spring-boot-starter-websocket

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

在配置类中增加websocket配置Bean

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;/*** @author yangnk* @desc* @date 2023/08/15 00:30**/
@Configuration
public class WebSocketConfig {@Beanpublic ServerEndpointExporter serverEndpointExporter() {return new ServerEndpointExporter();}
}

实现websocketServer

实现一个websocketserver,需要添加@ServerEndpoint(“/websocket/{name}”)注解,该注解需要加在类上,表示请求websocket的url地址,再实现websocket各个声明周期的注解的方法。

声明ConcurrentHashMap<String, WebSocketServer> webSocketMap用来保存websocket连接的session。

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.util.concurrent.ConcurrentHashMap;/*** @author yangnk* @desc* @date 2023/08/15 00:31**//*** @ServerEndpoint 注解的作用** @ServerEndpoint 注解是一个类层次的注解,它的功能主要是将目前的类定义成一个websocket服务器端,* 注解的值将被用于监听用户连接的终端访问URL地址,客户端可以通过这个URL来连接到WebSocket服务器端*/
@Slf4j
@Component
@ServerEndpoint("/websocket/{name}")
public class WebSocketServer {/*** 与某个客户端的连接对话,需要通过它来给客户端发送消息*/private Session session;/*** 标识当前连接客户端的用户名*/private String name;/*** 用于存所有的连接服务的客户端,这个对象存储是安全的* 注意这里的kv,设计的很巧妙,v刚好是本类 WebSocket (用来存放每个客户端对应的MyWebSocket对象)*/private static ConcurrentHashMap<String, WebSocketServer> webSocketMap = new ConcurrentHashMap<>();/*** 连接建立成功调用的方法* session为与某个客户端的连接会话,需要通过它来给客户端发送数据*/@OnOpenpublic void OnOpen(Session session, @PathParam(value = "name") String name){log.info("----------------------------------");this.session = session;this.name = name;// name是用来表示唯一客户端,如果需要指定发送,需要指定发送通过name来区分webSocketMap.put(name,this);log.info("[WebSocket] 连接成功,当前连接人数为:={}", webSocketMap.size());GroupSending(name+" 来了");}/*** 连接关闭调用的方法*/@OnClosepublic void OnClose(){webSocketMap.remove(this.name);log.info("[WebSocket] 退出成功,当前连接人数为:={}", webSocketMap.size());GroupSending(name+" 走了");}/*** 收到客户端消息后调用的方法*/@OnMessagepublic void OnMessage(String message_str){log.info("[WebSocket] 收到消息:{}",message_str);//判断是否需要指定发送,具体规则自定义//message_str的格式 TOUSER:user2;message:aaaaaaaaaaaaaaaaaa;if(message_str.indexOf("TOUSER") == 0){//取出 name和message的值String[] split = message_str.split(";");String[] split1 = split[0].split(":");String[] split2 = split[1].split(":");String name = split1[1];String message = split2[1];//指定发送AppointSending(name,message);}else{//群发GroupSending(message_str);}}/*** 发生错误时调用* @param session* @param error*/@OnErrorpublic void onError(Session session, Throwable error){log.info("发生错误");error.printStackTrace();}/*** 群发* @param message*/public void GroupSending(String message){for (String name : webSocketMap.keySet()){try {webSocketMap.get(name).session.getBasicRemote().sendText(name + ":" + message);}catch (Exception e){e.printStackTrace();}}}/*** 指定发送* @param name* @param message*/public void AppointSending(String name,String message){try {webSocketMap.get(name).session.getBasicRemote().sendText(name + ":" + message);}catch (Exception e){e.printStackTrace();}}
}

控制器Controller调用方法

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.HashMap;
import java.util.Map;
/*** @author yangnk* @desc* @date 2023/08/15 00:32**/@RestController("web_Scoket_system")
@RequestMapping("/api/socket")
public class SystemController {@AutowiredWebSocketServer socketServer;//推送数据接口@ResponseBody@RequestMapping("/socket/push/{name}")public String pushToWeb(@PathVariable String name, @RequestHeader String message) {Map<String,Object> result = new HashMap<>();socketServer.AppointSending(name, message);result.put("name", name);result.put("msg", message);return result.toString();}
}

验证结果

可以在在线websocket测试网站:https://www.bejson.com/httputil/websocket/ 进行验证。

image-20230816114918213

1.2.实现接口

TODO

2.完整代码

https://github.com/yangnk/SpringBoot_Learning/tree/master/SpringBootExample/src/main/java/com/yangnk/webSocketExample

3.常见问题

  1. websocket的默认超时实践为30min,如果需要长时间保持websocket连接,就需要设置保活机制。

TODO

  1. 补充通过实现接口的方式来使用websocket;

参考资料

  1. WebSocket:https://zh.wikipedia.org/zh-cn/WebSocket (官网)
  2. springboot整合websocket最基础入门使用教程详解:https://developer.aliyun.com/article/983651 (websocket demo写的比较详细,具有实操性)
  3. SpringBoot 集成 WebSocket,实现后台向前端推送信息:https://cloud.tencent.com/developer/article/1830998 (websocket demo写的不错)
  4. 一文了解WebSocket及Springboot集成WebSocket:https://developer.aliyun.com/article/1152716 (讲了比较多原理方面的东西)
  5. springboot整合webSocket(看完即入门):https://juejin.cn/post/7139334773356363783
  6. WebSocket使用介绍,看这篇就够了:https://juejin.cn/post/7244407068098560037#heading-6 (websocket的进阶使用)
  7. Java WebSocket 基础 生命周期:https://blog.csdn.net/sakuragio/article/details/98673473 (讲了非常详细的websocket事件和API使用情况)

本文由博客一文多发平台 OpenWrite 发布!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/47903.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

从一些常见的错误聊聊mysql服务端的关键配置 | 京东云技术团队

背景 每一年都进行大促前压测&#xff0c;每一次都需要再次关注到一些基础资源的使用问题&#xff0c;订单中心这边数据库比较多&#xff0c;最近频繁报数据库异常&#xff0c;所以对数据库一些配置问题也进行了研究&#xff0c;本文给出一些常见的数据库配置&#xff0c;说明…

(二)结构型模式:6、外观模式(Facade Pattern)(C++实例)

目录 1、外观模式&#xff08;Facade Pattern&#xff09;含义 2、外观模式的UML图学习 3、外观模式的应用场景 4、外观模式的优缺点 5、C实现外观模式的简单实例 1、外观模式&#xff08;Facade Pattern&#xff09;含义 外观模式&#xff08;Facade Pattern&#xff09;…

积跬步至千里 || 矩阵可视化

矩阵可视化 矩阵可以很方面地展示事物两两之间的关系&#xff0c;这种关系可以通过矩阵可视化的方式进行简单监控。 定义一个通用类 from matplotlib import pyplot as plt import seaborn as sns import numpy as np import pandas as pdclass matrix_monitor():def __init…

chatGPT-对话柏拉图

引言&#xff1a; 古希腊哲学家柏拉图&#xff0c;在他的众多著作中&#xff0c;尤以《理想国》为人所熟知。在这部杰作中&#xff0c;他勾勒了一个理想的政治制度&#xff0c;提出了各种政体&#xff0c;并阐述了他对于公正、智慧以及政治稳定的哲学观点。然而&#xff0c;其…

司徒理财:8.21黄金空头呈阶梯下移!今日操作策略

黄金走势分析 盘面裸k分析&#xff1a;1小时周期的行情局部于1896附近即下行通道上轨附近录得一系列的K线呈震荡下行并筑圆顶&#xff0c;上轨压制有效&#xff0c;下行通道并未突破&#xff0c;后市建议延续看下行。4小时周期局部录得一系列的纺锤线呈震荡&#xff0c;但行情整…

基于启扬RK3399核心板消防控制图形显示装置的解决方案

在我们日常生活中&#xff0c;火灾的发生是不可避免的风险之一&#xff0c;为了能及时发现火灾&#xff0c;并能够迅速采取措施进行灭火和救援&#xff0c;消防系统起着至关重要的作用。而在消防系统中&#xff0c;消防控制室图形显示装置是其中的重要组成部分之一。 消防控制图…

Mysql的事务

MySQL 事务 事务用于保证数据的一致性&#xff0c;它由一组相关的dml&#xff08;数据操作语言 增删改&#xff09;语句组成 该组的dml语句要么全部成功&#xff0c;要么全部失败。 -- 1. 创建一张测试表 CREATE TABLE t27( id INT,name VARCHAR(32));-- 2. 开始事务 START …

泰宁风景旅游区-泰宁旅游景点大全排名

泰宁旅游必去十大景点 泰宁景区是国家5A级景区&#xff0c;而且作为全国重点文物保护单位&#xff0c;该景区的游玩项目很多&#xff0c;比如说七大景区&#xff0c;当然了&#xff0c;原始生态为主要景观特点&#xff0c;集奇异性、多样性、休闲性、文化性为一身。那么如果到这…

数据结构,二叉树,前中后序遍历

二叉树的种类 最优二叉树 最优二叉树画法 排序取最小两个值和&#xff0c;得到新值加入排序重复1&#xff0c;2 前序、中序和后序遍历是树形数据结构&#xff08;如二叉树&#xff09;中常用的遍历方式&#xff0c;用于按照特定顺序遍历树的节点。这些遍历方式在不同应用中有不…

无涯教程-Perl - wantarray函数

描述 如果当前正在执行的函数的context正在寻找列表值,则此函数返回true。在标量context中返回false。 语法 以下是此函数的简单语法- wantarray返回值 如果没有context,则此函数返回undef&#xff1b;如果lvalue需要标量,则该函数返回0。 例 以下是显示其基本用法的示例…

Self-Alignment with Instruction Backtranslation

本文是LLM系列文章&#xff0c;针对《Self-Alignment with Instruction Backtranslation》的翻译。 指令反翻译的自动对齐 摘要1 引言2 方法3 实验4 不足5 相关工作6 结论 摘要 我们提出了一种可扩展的方法&#xff0c;通过用相应的指令自动标记人类书写的文本来建立高质量的…

当图像宽高为奇数时,如何计算 I420 格式的uv分量大小

背景 I420 中 yuv 数据存放在3个 planes 中。 网上一般说 I420 数据大小为 widthheight1.5 但是当 width 和 height 是奇数时&#xff0c;这个计算公式会有问题。 I420 中 u 和 v 的宽高分别为 y 的一半。 但是当不能整除时&#xff0c;是如何取整呢&#xff1f;向上还是向下&…

高忆管理:沪指震荡跌0.24%,医药、酿酒等板块走低,数据要素概念逆市活跃

22日早盘&#xff0c;两市股指高开低走&#xff0c;沪指盘中冲高回落&#xff0c;创业板指走势疲弱&#xff1b;北向资金净卖出超40亿元。 到午间收盘&#xff0c;沪指跌0.24%报3085.48点&#xff0c;深成指跌0.73%&#xff0c;创业板指跌1.3%&#xff1b;两市合计成交4510亿元…

【李宏毅机器学习】注意力机制

输出 我们会遇到不同的任务&#xff0c;针对输出的不一样&#xff0c;我们对任务进行划分 给多少输出多少 给一堆向量&#xff0c;输出一个label&#xff0c;比如说情感分析 还有一种任务是由机器决定的要输出多少个label&#xff0c;seq2seq的任务就是这种&#xff0c;翻译也…

js数组操作的shift unshift pop push用法

Array.shift() shift() 方法用在数组上&#xff0c; 移除数组的第一个元素并返回移除的元素. 该方法会改变原数组的长度. const array1 [1, 2, 3];const firstElement array1.shift();console.log(array1); // Expected output: Array [2, 3]console.log(firstElement); …

Java List的扩容机制原理及应用

Java List的扩容机制原理及应用 引言 在Java中&#xff0c;List是一种非常常用的数据结构&#xff0c;用于存储有序的元素集合。List的底层实现有多种&#xff0c;如ArrayList、LinkedList等。在使用List时&#xff0c;我们经常会遇到一个问题&#xff1a;当元素数量超过了Li…

docker 03(docker 容器的数据卷)

一、数据卷的概念和作用 删除后&#xff0c;数据也没了。 不能 数据卷 是宿主机中的一个目录或文件当容器目录和数据卷目录绑定后&#xff0c;对方的修改会立即同步一个数据卷可以被多个容器同时挂载 作用&#xff1a; 容器数据持久化 外部机器和容器间接通信 容器之间数据交换…

无人机空管电台-中大型无人机远程VHF语音电台系统

方案背景 中大型无人机在执行飞行任务时&#xff0c;特别是在管制空域飞行时地面航管人员需要通过语音与无人机通信。按《无人驾驶航空器飞行管理暂行条例》规定&#xff0c;中大型无人机应当进行适航管理。物流无人机和载人eVTOL都将进行适航管理&#xff0c;所以无人机也要有…

robotframework如何做接口测试?

robotframework(后续简称为robot)是一款自动化测试框架&#xff0c;可能做各种类型的自动化测试。 本文介绍通过robotframework来做接口测试。 在robot当中&#xff0c;python语言的接口测试库名称为RequestsLibrary 安装语法如下&#xff1a; pip install -U requests pip …

Window下部署使用Stable Diffusion AI开源项目绘图

Window下部署使用Stable Diffusion AI开源项目绘图 前言前提条件相关介绍Stable Diffusion AI绘图下载项目环境要求环境下载运行项目打开网址&#xff0c;即可体验文字生成图像&#xff08;txt2img&#xff09;庐山瀑布 参考 本文里面的风景图&#xff0c;均由Stable Diffusion…