WebSocket实现前后端双向数据的实时推送

一、WebSocket简介

        WebSocket是一种网络通信协议,旨在实现客户端和服务器之间的双向、全双工通信。它在HTML5规范中被引入,用于替代基于传统HTTP协议的长轮询、轮询和流传输等方式,以提供更高效的实时数据传输。

WebSocket的特点

  1. 双向通信:与传统的HTTP协议不同,WebSocket允许客户端和服务器之间的双向通信。客户端和服务器都可以在任何时候发送数据,而无需等待对方先发起请求。

  2. 持久连接:WebSocket连接一旦建立,将会保持打开状态,直到客户端或服务器主动关闭连接。这减少了因频繁建立和关闭连接带来的开销。

  3. 低延迟:由于WebSocket减少了请求头信息和频繁的握手过程,通信延迟显著降低,非常适合实时应用。

  4. 基于消息:WebSocket通信是基于消息的,而不是基于请求-响应。这样可以更加灵活地传输数据。

WebSocket的工作原理

  1. 握手阶段:客户端通过HTTP请求向服务器发起WebSocket握手请求。这个请求包含一个特殊的Upgrade头部,指示服务器将连接从HTTP升级到WebSocket协议。

  2. 建立连接:服务器收到握手请求后,如果同意升级连接,则会返回一个101状态码的响应,表示协议切换成功。此时,WebSocket连接正式建立。

  3. 数据传输:连接建立后,客户端和服务器可以通过WebSocket协议相互发送消息。这些消息可以是文本或二进制数据。

  4. 关闭连接:当任意一方不再需要连接时,可以发送关闭请求来关闭WebSocket连接。连接关闭后,通信停止,资源释放。

二、数据实时推送的实现方式和应用场景

轮询 (Polling)

优点
  1. 实现简单:实现和理解起来相对容易,使用传统的HTTP请求。
  2. 浏览器兼容性好:几乎所有浏览器都支持,适用于所有的客户端。
缺点
  1. 资源浪费:频繁的HTTP请求会消耗大量带宽和服务器资源,即使没有新数据时也会发送请求。
  2. 延迟高:实时性差,因为需要等待下一个请求周期才能获取新数据。
使用场景
  • 适用于低频更新和对实时性要求不高的应用,如定时刷新页面内容。

长连接 (HTTP Persistent Connection)

优点
  1. 减少开销:在同一个TCP连接上进行多个HTTP请求,减少了建立和关闭连接的开销。
  2. 提高效率:适用于连续请求的场景,提高了传输效率。
缺点
  1. 资源占用:服务器需要维护连接状态,占用资源。
  2. 不适合实时通信:虽然减少了建立连接的开销,但仍然是基于请求-响应模式,实时性不如WebSocket。
使用场景
  • 适用于需要频繁请求数据的应用,如加载大量静态资源的网页。

WebSocket

优点
  1. 双向通信:客户端和服务器都可以主动发送消息,实现全双工通信。
  2. 低延迟:一旦连接建立,数据可以实时传输,延迟极低。
  3. 高效:减少了HTTP头部和握手的开销,适合高频率的数据传输。
缺点
  1. 复杂度高:实现和维护起来比轮询复杂,需要处理连接管理、心跳检测等。
  2. 浏览器兼容性:虽然现代浏览器都支持,但在非常旧的浏览器上可能不支持。
使用场景
  • 适用于高频率和低延迟的实时应用,如在线游戏、实时聊天、股票行情、协作编辑。

三、代码实现

1.pom.xml添加WebSocke依赖

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

 2.WebSocke配置类

package com.example.websocketdemo;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 // 启用WebSocket支持
public class WebSocketConfig implements WebSocketConfigurer {@Overridepublic void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {// 注册WebSocket处理程序,并设置WebSocket路径为 "/websocket"registry.addHandler(new MyWebSocketHandler(), "/websocket").setAllowedOrigins("*");}
}

 3.WebSocke服务类

package com.example.websocketdemo;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;import java.util.Collections;
import java.util.HashSet;
import java.util.Set;public class MyWebSocketHandler extends TextWebSocketHandler {// 用于存储所有活动的WebSocket会话private static final Set<WebSocketSession> sessions = Collections.synchronizedSet(new HashSet<>());// 处理接收到的文本消息@Overrideprotected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {String payload = message.getPayload(); // 获取消息内容System.out.println("Received: " + payload); // 打印接收到的消息session.sendMessage(new TextMessage("Server received: " + payload)); // 回复消息给客户端// 发送当前连接人数broadcast("Current number of connections: " + sessions.size());}// 处理WebSocket连接建立@Overridepublic void afterConnectionEstablished(WebSocketSession session) throws Exception {sessions.add(session); // 添加会话到集合System.out.println("Connected: " + session.getId());// 发送当前连接人数broadcast("New connection established. Current number of connections: " + sessions.size());}// 处理WebSocket连接关闭@Overridepublic void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {sessions.remove(session); // 从集合中移除会话System.out.println("Disconnected: " + session.getId());// 发送当前连接人数broadcast("Connection closed. Current number of connections: " + sessions.size());}// 向所有连接的客户端广播消息private void broadcast(String message) {for (WebSocketSession session : sessions) {if (session.isOpen()) {try {session.sendMessage(new TextMessage(message));} catch (Exception e) {e.printStackTrace();}}}}
}

  3.创建启动类

package com.example.websocketdemo;import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;@SpringBootApplication
public class WebsocketDemoApplication {public static void main(String[] args) {SpringApplication.run(WebsocketDemoApplication.class, args); // 启动Spring Boot应用}
}

四、测试WebSocket连接

可以使用浏览器的控制台进行测试:

let socket = new WebSocket("ws://localhost:8080/websocket");socket.onopen = function(e) {console.log("[open] Connection established");socket.send("Hello Server!"); // 发送消息给服务器
};socket.onmessage = function(event) {console.log(`[message] Data received from server: ${event.data}`); // 处理服务器返回的消息
};socket.onclose = function(event) {if (event.wasClean) {console.log(`[close] Connection closed cleanly, code=${event.code} reason=${event.reason}`);} else {console.error('[close] Connection died'); // 处理连接关闭}
};socket.onerror = function(error) {console.error(`[error] ${error.message}`); // 处理错误
};

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

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

相关文章

Python 3 判断文件是否存在

1 使用os.path模块 import osfile_path hello.txtif os.path.exists(file_path):print(f"文件 {file_path} 存在。") else:print(f"文件 {file_path} 不存在。") 2 使用pathlib模块 from pathlib import Pathfile_path Path(word.txt)if file_path.ex…

32-ESP32-S3-WIFI篇-03 Event Loop (事件循环)

ESP32-S3-WIFI 事件循环 介绍 在ESP32-S3的WiFi驱动程序中&#xff0c;事件循环是一个非常重要的概念。事件循环是一个无限循环&#xff0c;用于处理和分发系统中发生的各种事件。在WiFi驱动程序中&#xff0c;我们使用事件循环来处理和分发WiFi相关的事件。 创建事件循环 …

PTA 7-10 构造二叉检索树

本题目构造一棵二叉检索树。要求读入n个整数&#xff0c;以0结束。最后输出这棵树的先序序列。 输入格式: 输入n个整数&#xff0c;以0表示结束&#xff0c;数据间以空格隔开。 输出格式: 输出这棵树的先序序列&#xff0c;以一个空格隔开&#xff0c;结尾也有一个空格。 …

常用电机测试方法的介绍与功能实现(M测试方法)

目录 概述 1 常用电机测速方法简介 1.1 方法概览 1.2 编码器测速方法 2 M法测速 2.1 理论描述 2.2 实现原理 2.3 速度计算方法 3 功能实现 3.1 功能介绍 3.2 代码实现 3.2.1 使用STM32Cube配置参数 3.2.2 脉冲计数功能 3.2.3 测速函数 4 测试 概述 本文主要介绍…

springboot针对返回的response拦截处理越权问题

背景&#xff1a;针对越权测试&#xff0c;通过拦截工具Fiddler修改请求参数&#xff0c;越权查看平台里面所有公司的数据 1、自定义MyResponseBodyAdvice 实现ResponseBodyAdvice 使用过滤器和拦截我都试过&#xff0c;最终没有成功&#xff0c;可能技术比较菜&#xff0c;这…

策略模式解析

import java.util.*; enum TYPE { NORMAL,CASH_DISCOUNT,CASH_RETURN}; interface Cashsuper { public double acceptCash(double money); } class CashNormal implements CashSuper{// 正常收费子类 public double accptCash(double money){ return money; …

C# Winform 已知窗体句柄,如何遍历出所有控件句柄

c# windform 已知窗体句柄&#xff0c;如何遍历出所有控件句柄 public delegate bool CallBack(int hwnd, int lParam);public delegate bool EnumWindowsProc(int hWnd, int lParam); List<string> list new List<string>();[DllImport("user32.dll")]…

通过MySQL JSON函数实现对GSON字段属性的搜索和筛选

在 MySQL 中直接对 Gson 格式的字段进行搜索是有一定的限制的&#xff0c;因为 MySQL 不支持直接解析和操作 JSON 或 Gson 数据。不过你可以使用一些函数来模拟实现对 Gson 字段内部某个属性的搜索&#xff0c;比如使用 LIKE 来做模糊匹配。 假设你的表名为 gson_table&#x…

GPT-4o版本间的对比分析和使用心得

GPT-4o&#xff1a;对人工智能领域的新贡献 GPT-4o是OpenAI最新发布的语言模型&#xff0c;相比于其前身GPT-4和更早的版本GPT-3&#xff0c;具有显著的改进和增强。以下是对GPT-4o的详细评价&#xff0c;包括版本间的对比分析、技术能力的提升&#xff0c;以及我在实际使用过…

黑马一站制造数仓实战2

问题 DG连接问题 原理&#xff1a;JDBC&#xff1a;用Java代码连接数据库 Hive/SparkSQL&#xff1a;端口有区别 可以为同一个端口&#xff0c;只要不在同一台机器 项目&#xff1a;一台机器 HiveServer&#xff1a;10000 hiveserver.port 10000 SparkSQL&#xff1a;10001…

谈谈Android AOP技术方案

先统一一下基本名词&#xff0c;以便表述。 切面&#xff1a;对一类行为的抽象&#xff0c;是切点的集合&#xff0c;比如在用户访问所有模块前做的权限认证。 切点&#xff1a;描述切面的具体的一个业务场景。 通知&#xff08;Advice&#xff09;类型&#xff1a;通常分为切…

一维时间序列信号的广义傅里叶族变换(Matlab)

广义傅里叶族变换是一种时频变换方法&#xff0c;傅里叶变换、短时傅里叶变换、S变换和许多小波变换都是其特殊情况&#xff0c;完整代码及子函数如下&#xff0c;很容易读懂&#xff1a; % Run a demo by creating a signal, transforming it, and plotting the results% Cre…

不同厂商SOC芯片在视频记录仪领域的应用

不同SoC公司芯片在不同产品上的应用信息&#xff1a; 大唐半导体 芯片型号: LC1860C (主控) LC1160 (PMU)产品应用: 红米2A (399元)大疆晓Spark技术规格: 28nm工艺&#xff0c;4个ARM Cortex-A7处理器&#xff0c;1.5GHz主频&#xff0c;2核MaliT628 GPU&#xff0c;1300万像…

计算属性与监听属性

【 1 】计算属性 计算属性大致就是这样 # 1 计算属性是基于它们的依赖进行缓存的# 2 计算属性只有在它的相关依赖发生改变时才会重新求值# 3 计算属性就像Python中的property&#xff0c;可以把方法/函数伪装成属性 # 计算属性本质上是一个函数&#xff0c;它们可以通过 get…

数据隐私新篇章:Facebook如何保护用户信息

随着数字化时代的到来&#xff0c;数据隐私保护成为了社交媒体平台和用户共同关注的焦点。作为全球最大的社交网络之一&#xff0c;Facebook一直致力于保护用户的隐私和数据安全。本文将深入探讨Facebook在数据隐私保护方面的措施和实践&#xff0c;以及其如何开启数据隐私的新…

vue实现简易基本对话功能

基于vue3.0实现的功能&#xff0c;仿照微信、QQ聊天界面。 HTML代码块 <template><el-container style"height: 100%" ref"bodyform"><div class"el_main_content"><div class"main_content_header">这是一…

Git基本配置,使用Gitee(一)

1、设置Giter的user name和email 设置提交用户的信息 git config --global user.name "username" git config --global user.email "Your e-mail"查看配置 git config --list2、生成 SSH 公钥 通过命令 ssh-keygen 生成 SSH Key -t key 类型 -C 注释 ssh-…

K8S 证书过期不能使用kubectl之后,kubeadm 重新生成证书

查询证书过期时间 kubeadm certs check-expiration重新生成证书 # 重新生成所有证书 kubeadm certs renew all # 重新生成某个组件的证书 kubeadm certs renew 组件名称 如&#xff1a;apiserver生成新的配置 # 重新生成kubeconfig配置 kubeadm init phase kubeconfig # 重…

LabVIEW中PID控制器系统的噪声与扰动抑制策略

在LabVIEW中处理PID控制器系统中的噪声和外部扰动&#xff0c;需要从信号处理、控制算法优化、硬件滤波和系统设计四个角度入手。采用滤波技术、调节PID参数、增加前馈控制和实施硬件滤波器等方法&#xff0c;可以有效减少噪声和扰动对系统性能的影响&#xff0c;提高控制系统的…

原生小程序一键获取手机号

1.效果图 2.代码index.wxml <!-- 获取手机号 利用手机号快速填写的功能&#xff0c;将button组件 open-type 的值设置为 getPhoneNumber--><button open-type"getPhoneNumber" bindgetphonenumber"getPhoneNumber">获取手机号</button> …