WebSocket通信学习笔记

1 简介

WebSocket是一种全双工通信协议,它允许客户端和服务器之间建立持久化的双向连接,从而在不频繁创建HTTP请求的情况下进行实时数据传输。与传统的HTTP协议相比,WebSocket更适合需要实时数据更新的应用场景,如聊天应用、实时股票行情、在线游戏等。
WebSocket 是基于 TCP 的一种新的网络协议。它实现了浏览器与服务器全双工通信——浏览器和服务器只需要完成一次握手,两者之间就可以创建持久性的连接, 并进行双向数据传输。
WebSocket可以通过wss://前缀实现加密通信,类似于HTTPS。由于WebSocket协议本身没有对数据的加密和身份验证机制,因此在使用时通常结合TLS/SSL进行加密,并通过认证机制确保通信的安全性。

1.1 工作原理

1) 握手阶段

WebSocket连接从客户端发起一个标准的HTTP请求开始,但这个请求的头部包含一些额外的字段,表示客户端希望升级到WebSocket协议。这是一个GET请求,并且包含以下几个重要的头部字段:

  • Upgrade: websocket:表示客户端希望将这个连接升级为WebSocket。
  • Connection: Upgrade:与Upgrade字段配合使用,表明连接类型的变化。
  • Sec-WebSocket-Key:一个由客户端生成的随机的Base64编码的key,服务器将用它来生成一个响应密钥以确认握手。
  • Sec-WebSocket-Version:表示WebSocket协议的版本,通常为13。

2) 服务器响应

如果服务器支持WebSocket,它将回应一个HTTP 101状态码,表示协议切换成功,并且在响应头部包含以下字段:

  • Upgrade: websocket:确认协议升级。
  • Connection: Upgrade:与Upgrade字段配合使用。
  • Sec-WebSocket-Accept:服务器根据客户端提供的Sec-WebSocket-Key,加上一个固定的字符串,然后通过SHA-1加密并进行Base64编码后生成的值。这个值用于确认握手的有效性。

握手完成后,连接正式切换为WebSocket协议,客户端和服务器可以开始通过这个持久连接进行双向通信。

3) 数据帧传输

一旦连接建立,客户端和服务器之间的数据传输以帧的形式进行。WebSocket的数据帧由一个小的头部和可变长度的数据负载组成,帧可以携带文本数据(UTF-8编码的字符串)或二进制数据。WebSocket支持以下几种帧类型:

  • 文本帧:用于传输文本数据。
  • 二进制帧:用于传输二进制数据。
  • 关闭帧:用于表示连接关闭。
  • Ping帧:客户端或服务器发送Ping帧以测试连接的连通性。
  • Pong帧:用于响应Ping帧。

4) 连接关闭

WebSocket连接可以由客户端或服务器任意一方发起关闭。关闭连接时,必须发送一个关闭帧,其中可以包含关闭码和关闭原因。收到关闭帧后,另一方应尽快发送自己的关闭帧并关闭连接。

1.2 WebSocket 优缺点分析

1)优点

  • 低延迟:由于WebSocket连接是持久的,消除了频繁创建和关闭连接的开销,延迟较低,非常适合需要实时数据更新的应用。
  • 全双工通信:与HTTP的请求-响应模式不同,WebSocket支持全双工通信,客户端和服务器可以同时发送和接收消息。
  • 节省带宽:WebSocket在建立连接后没有HTTP协议的头部负载,可以节省带宽。

2) 缺点

  • 复杂性:WebSocket的实现和调试可能比传统的HTTP协议要复杂,尤其是在处理连接状态、网络问题和安全性方面。
  • 不适用于所有应用:对于一些不需要实时通信的应用,WebSocket可能显得过于复杂和不必要。

1.3 适用场景

  • 实时聊天应用:WebSocket可以实现低延迟的消息传递,非常适合实时聊天。
  • 实时推送:如新闻、体育比分、金融市场数据等。
  • 多人在线游戏:需要低延迟的数据同步和通信。
  • 协作编辑工具:如在线文档编辑、代码协作等,WebSocket可以实现实时的内容同步。

对比 HTTP:

  • HTTP适用于大多数Web应用和API场景,其简单的请求-响应模型、无状态特性和广泛的工具支持,使其成为Web开发的标准选择。
  • WebSocket则适合需要实时、双向数据传输的应用场景,如聊天、在线游戏和金融数据推送。虽然实现上更为复杂,但其在特定场景下的性能和效率优势是HTTP无法比拟的。

详细比较:

  • **通信模式:**HTTP 是请求-响应模式,单项且无状态的;WebSocket 是全双工通信,双向且持续连接。
  • **连接管理:**HTTP通常是短连接,每次请求都重新建立连接;WebSocket是长连接,握手后保持连接,适合频繁数据交换。
  • **使用场景:**HTTP适用于网页加载、API调用等不需要实时更新的场景;WebSocket适用于实时聊天、在线游戏等需要低延迟、实时数据更新的应用。

HTTP和WebSocket底层都是TCP连接。

2 Demo 实例

1) 创建 SpringBoot 项目

2) 引入 Maven 依赖

<!--导入websocket依赖-->
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-websocket</artifactId>
</dependency>

3) 导入前端页面

<!DOCTYPE HTML>
<html><head><meta charset="UTF-8"><title>WebSocket Demo</title></head><body><input id="text" type="text" /><button onclick="send()">发送消息</button><button onclick="closeWebSocket()">关闭连接</button><div id="message"></div></body><script type="text/javascript">var websocket = null;var clientId = Math.random().toString(36).substr(2);//判断当前浏览器是否支持WebSocketif('WebSocket' in window){//连接WebSocket节点websocket = new WebSocket("ws://localhost:8080/ws/"+clientId);}else{alert('Not support websocket')}//连接发生错误的回调方法websocket.onerror = function(){setMessageInnerHTML("error");};//连接成功建立的回调方法websocket.onopen = function(){setMessageInnerHTML("连接成功");}//接收到消息的回调方法websocket.onmessage = function(event){setMessageInnerHTML(event.data);}//连接关闭的回调方法websocket.onclose = function(){setMessageInnerHTML("close");}//监听窗口关闭事件,当窗口关闭时,主动去关闭websocket连接,防止连接还没断开就关闭窗口,server端会抛异常。window.onbeforeunload = function(){websocket.close();}//将消息显示在网页上function setMessageInnerHTML(innerHTML){document.getElementById('message').innerHTML += innerHTML + '<br/>';}//发送消息function send(){var message = document.getElementById('text').value;websocket.send(message);}//关闭连接function closeWebSocket() {websocket.close();}</script>
</html>

4) 编写后端 websocket 服务类

@Component
@ServerEndpoint("/ws/{sid}")
public class WebSocketServer {// 存放会话对象private static Map<String, Session> sessionMap = new HashMap<>();/*** 连接建立成功调用的方法*/@OnOpenpublic void onOpen(Session session, @PathParam("sid") String sid) {System.out.println("客户端:" + sid + "建立连接");sessionMap.put(sid, session);}/*** 收到客户端消息后调用的方法*/@OnMessagepublic void onMessage(String message, @PathParam("sid") String sid) {System.out.println("收到来自客户端:" + sid + "的信息:" + message);}/*** 连接关闭调用的方法*/@OnClosepublic void onClose(@PathParam("sid") String sid) {System.out.println("连接断开:" + sid);sessionMap.remove(sid);}/*** 群发*/public void sendToAllClient(String message) {Collection<Session> sessions = sessionMap.values();for (Session session : sessions) {try {// 服务器向客户端发送消息session.getBasicRemote().sendText(message);} catch (Exception e) {e.printStackTrace();}}}
}

5)编写 websocket 配置类

这个配置类的主要作用是启用WebSocket支持。当Spring容器启动时,它会自动扫描所有标记了@ServerEndpoint注解的类,并将它们注册为WebSocket端点,允许客户端通过这些端点进行WebSocket通信。 如果你在Spring Boot项目中使用内置的Web容器(如Tomcat、Jetty等),并且使用WebSocket,则需要这个ServerEndpointExporter来将WebSocket端点自动注册到容器中。

@Configuration
public class WebSocketConfiguration {@Beanpublic ServerEndpointExporter serverEndpointExporter() {return new ServerEndpointExporter();}
}

6) 定时任务模拟后端发送给用户端消息

@Component
public class WebSocketTask {@Autowiredprivate WebSocketServer webSocketServer;/*** 通过websocket每隔五秒向客户发送信息*/@Scheduled(cron = "0/5 * * * * ?")public void sendMessageToClient() {webSocketServer.sendToAllClient("这是来自服务端的消息" + DateTimeFormatter.ofPattern("HH:mm:ss").format(LocalDateTime.now()));}
}

3 结果展示

前端结果:
除了自己能主动给后端发送信息以外,前段每隔五秒还能收到后端发来的信息。
image.png
后端结果:
服务端自动接收前段发来的信息,同时会在定时任务中,每隔五秒给前端发送一条信息。
image.png
代码获取:https://gitee.com/strivezhangp/java-study-log.git 切换到相关分支即可拉取。

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

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

相关文章

【Kafka】Windows下安装Kafka(全面)

目录 1.前提条件 2.下载 3.安装 4.环境变量配置 5.验证 1.前提条件 1.先安装zookeeper&#xff1a; 【Zookeeper】Windows下安装Zookeeper&#xff08;全面&#xff09;-CSDN博客https://blog.csdn.net/weixin_57259781/article/details/141679454 2.还需要安装scala: …

虚幻5|技能栏UI优化(2)——优化技能UI并实现技能栏的拖拽操作

这篇文章里&#xff0c;前情提要&#xff0c;文章里的序列变量应命名为序号&#xff0c;我命名错了&#xff0c;虽然不差&#xff0c;但为了后面更好的理解 一.刷新技能栏&#xff0c;用于刷新上一章文章的初始化技能栏 1.打开技能栏格子&#xff0c;打开图表&#xff0c;添加…

【数学建模学习手册】python基本入门使用

本专栏内容为&#xff1a;数学建模原理 记录学习数学建模 &#x1f493;博主csdn个人主页&#xff1a;小小unicorn ⏩专栏分类&#xff1a;数学建模 &#x1f69a;代码仓库&#xff1a;小小unicorn的代码仓库&#x1f69a; &#x1f339;&#x1f339;&#x1f339;关注我带你学…

Cycle inside Runner; building could produce unreliable results.

报错 Showing Recent Messages Cycle inside Runner; building could produce unreliable results. Cycle details: → Target Runner ○ That command depends on command in Target Runner: script phase “Thin Binary” ○ Target Runner has process command with outpu…

Oracle taf高级特性使用

0、taf介绍 TAF是Oracle数据库提供的一个高级特性&#xff0c;旨在实现应用程序在数据库连接中断时的透明重连。它允许应用程序在数据库故障发生时&#xff0c;无需修改代码或手动干预&#xff0c;就能自动连接到新的数据库实例&#xff0c;保证了事务的连续性和应用的高可用性…

Python编码—掌握Python与Kubernetes:构建高效微服务架构

&#x1f31f;&#x1f31f; 欢迎来到我的技术小筑&#xff0c;一个专为技术探索者打造的交流空间。在这里&#xff0c;我们不仅分享代码的智慧&#xff0c;还探讨技术的深度与广度。无论您是资深开发者还是技术新手&#xff0c;这里都有一片属于您的天空。让我们在知识的海洋中…

开源搜索引擎之Solr

Apache Solr 是一个开源的企业级搜索平台&#xff0c;构建在 Apache Lucene 之上&#xff0c;提供了强大的全文搜索、实时索引和分布式搜索能力。Solr 被广泛用于构建高性能的搜索应用程序&#xff0c;支持从简单的搜索引擎到复杂的数据分析平台等多种场景。以下是对 Apache So…

Linux学习笔记(4)----Debian压力测试方法

使用命令行终端压力测试需要两个实用工具&#xff1a;s-tui和stress sudo apt install s-tui stress 安装完成后&#xff0c;在终端中启动 s-tui实用工具&#xff1a; s-tui 执行后如下图&#xff1a; 你可以使用鼠标或键盘箭头键浏览菜单&#xff0c;然后点击“压力选项(Str…

类在JVM中的工作原理

文章目录 引言I 类在JVM中的工作原理class文件的结构类的生命周期II JVM运行时数据区堆栈的意义栈帧内部结构堆III 在JIT中比较常见的优化手段引言 类是一种抽象概念,它是一种模板,用来定义一类事物的属性和行为。类是面向对象编程的基础,它是一种抽象的概念,代表一类事物…

科技赋能 重塑未来医疗丨共谋医疗信息化新方向,2024东北医院信息网络大会圆满落幕!

近年来&#xff0c;随着我国医疗行业信息化的飞跃式发展&#xff0c;医疗信息化已经成为推动医疗行业高质量发展的重要力量之一。自2021年国家卫健委、中医药管理局联合印发《公立医院高质量发展促进行动&#xff08;2021-2025年&#xff09;》以来&#xff0c;各医疗机构将建设…

Ant Design Vue中Modal.confirm无法自动关闭

温馨tips:着急看解决方法可跳过碎碎念~ 前两天经理扔给我一个问题&#xff1a;“这个弹窗怎么关不上了&#xff1f;” 我怀着无所谓的心态&#xff1a;小意思啦&#xff0c;5分钟之内解决完~ …当然flag是不能随便乱立的 拉下来项目&#xff08;原神启动&#xff08;不是&…

商家推广怎么利用C#发送视频短信

视频短信&#xff0c;这一融合了视频、音频与文本的创新通信方式&#xff0c;不仅革新了传统短信的单一形式&#xff0c;更以其独特的魅力带领着移动通信的新风尚。它以移动视频格式为载体&#xff0c;实现了信息传输的多元化&#xff0c;为用户带来不一样的通信体验。 支持免费…

layui栅格布局设置列间距不起作用

layui栅格布局支持设置列间距&#xff0c;只需使用预置类layui-col-space*即可。不过实际使用时却始终看不到效果。   根据layui官网文档的说明&#xff0c;只需要在行所在div元素的class属性中增加layui-col-space*即可出现列间距。如下图所示&#xff1a;   但是实际使用…

2024 年顶级 Flutter UI 框架和库

根据 2022 年 StackOverflow 调查显示&#xff0c;Flutter 是最受欢迎的跨平台工具之一。自发布以来的 16 个月内&#xff0c;已有超过 200 万开发者采用了 Flutter。在本博客中&#xff0c;我们将浏览 GitHub 上可用的顶级 Flutter 存储库。除了每个存储库之外&#xff0c;还提…

Navicat Lite导入为SQL,然后到服务器的SQLServer Management 里执行时,报各种错误,是文件的Encoding不一致导致的解决

1、好多时候&#xff0c;本地的操作系统与服务器的操作系统不一致&#xff0c;有的时候也是历史原因&#xff0c;我们不得不用老旧的版本的数据库&#xff0c;比如 SQLServer 2008R2的数据库系统。 2、然后本地因为操作系统是win11的&#xff0c;导致这个SQLServer 2008R2根本…

萤石云 C++ SDK使用指南

今天继续指南系列&#xff0c;给出了萤石云QtDemo配置使用以及sdk开发中常见问题的指南 SDK下载 一、demo使用配置 1、demo环境配置 Demo 所使用Qt SDK版本&#xff1a;Qt4.8.5 Demo两种开发模式&#xff1a; 下载Qt Creator for Windows&#xff0c;使用Qt Creator作为I…

USR-DR134有人网关如何对接到ThingsPanel

本指南将帮助您使用有人口红串口服务器USR-DR134/USR-DR132将断路器接入ThingsPanel平台。这款创新的超小体积导轨式单串口服务器能够实现RS485/RS232转以太网的双向透传功能&#xff0c;是连接断路器与物联网平台的理想选择。 设备介绍&#xff1a; 口红串口服务器USR-DR134…

解析 uni-app 小程序分包策略:合理优化包体积分布

引言 微信小程序的流行使得越来越多的开发者投入到小程序的开发中。但是&#xff0c;随着项目规模的增大&#xff0c;小程序的性能也会面临一些挑战。其中&#xff0c;小程序分包策略是提升性能的重要一环。 同时&#xff0c;uni-app 的流行也使众多的移动端开发者选择使用 u…

零基础入门转录组数据分析——单基因ROC分析

零基础入门转录组数据分析——单基因ROC分析 目录 零基础入门转录组数据分析——单基因ROC分析1. ROC分析的基础知识2. 单基因ROC分析&#xff08;Rstudio&#xff09;——代码实操2. 1 数据处理2. 2 单基因ROC分析2. 3 ROC曲线简单可视化 1. ROC分析的基础知识 1.1 ROC分析是…

如何在忘记密码或 ID 的情况下解锁 iPhone 15

您是否曾经因为忘记了 iPhone 密码而陷入困境&#xff0c;或者您是否多次错误地输入了屏幕时间密码并发现自己被锁定在 iPhone 之外&#xff1f; 被锁定和拒绝访问您的 iPhone 可能很常见&#xff0c;尤其是在您尚未配置 Face ID 的情况下。或者&#xff0c;如果 Face ID 无法正…