webSocket原理及其案例

常见的消息推送方式

1:轮询方式

浏览器以指定的时间间隔向服务器发出HTTP请求,服务器实现试试返回数据给浏览器

缺点:数据有延时、服务器压力较大。

2:长轮询

浏览器发出ajax(异步)请求,服务器接收端接收到请求后,会阻塞请求直到有数据或者超时才返回。

缺点:

3:SSE服务器发送事件

SSE在服务器和客户端之间打开一个单向通道

服务端响应的不再是一次性的数据包,而是Text/event-stream类型的数据流信息

服务器有数据变更时将数据流式传输到客户端

4:webSocket

基于TCP连接上及逆行全双工通信的协议

全双工:允许数据在两个方向上同时传输。

半双工:允许数据在两个方向上传输,但是同一个时间段内只允许一个方向上的传输。

websocket API

客户端【浏览器】API

websocket对象提供的方法

send() 通过websocket对象调用该方法发送数据给服务端

案例

服务端API

Tomcat从7.0.5才支持websocket

Java WebSocket应用由一系列的Endpoint组成,Endpoint是一个Java对象,代表WebSocket链接的一端,对于服务端,我们可以视为处理具体websocket消息的接口

定义Endpoint两种方式:

编程式,继承类javax.websocket.Endpoint并实现其方法。

注解式,定义一个POJO,并添加@ServiceEndpoint相关注解。

Endpoint实例在WebSocket握手时创建,并在客户端于服务端链接过程中有效,最后在链接关闭时结束。在Endpoint接口中明确定义了与其生命周期相关的方法,规范实现者确保生命周期的各个阶段调用示例的相关方法,生命周期方法如下:

方法描述注解
onOpen()当开启一个新的会话时调用,该方法是客户端与服务端握手成功后调用的方法@OnOpen
onClose()当会话关闭时调用@OnClose
onError()当连接过程异常时调用@OnError

两个问题

服务端如何接收客户端发送的数据呢?

1:编程式

通过添加MessageHandler消息处理器来接收消息

2:注解式

在定义Endpoint时,通过@OnMessage注解指定接收消息的方法

服务端如何推送数据给客户端呢?

发送消息则由RemoteEndpoint完成,其实例由Session维护。

发送消息有两种方式

1:通过session.getBasicRemote获取同步消息发送的实例,然后调用其sendXxx()方法发送消息

2:通过session.getAsyncRemote获取异步消息发送实例,然后调用其sendXxx()方法发送消息

例子

代码实现

引入依赖资源

<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-websocket</artifactId><version>2.0.0.RELEASE</version>
</dependency>

编写配置类,扫描添加有@ServerEndpoint注解的Bean

@Configuration
public class FileManageWebSocketConfigMessage {/*** 注入ServerEndpointExporter,自动注册使用@ServerEndpoint注解的* @return*/public ServerEndpointExporter serverEndpointExporter(){return new ServerEndpointExporter();}
}

编写配置类,获取HttpSession对象

public class GetHttpSessionConfigurator extends ServerEndpointConfig.Configurator {public void modifyHandshake(ServerEndpointConfig config, HandshakeRequest request, HandshakeResponse response) {//强转HttpSession httpSession =(HttpSession) request.getHttpSession();//将httpSession对象存储到配置对象中config.getUserProperties().put(HttpSession.class.getName(),httpSession);}

使用

在@ServerEndpoint注解种引入配置器

@ServerEndpoint(value="/chat",configurator = GetHttpSessionConfigurator.class)

案例代码

webSocket.util

import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;import javax.websocket.OnClose;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArraySet;@Component
@ServerEndpoint("/webSocket/{uId}")
@Slf4j
public class WebSocketServerUtil {private Session session;private static CopyOnWriteArraySet<WebSocketServerUtil > webSocketSet = new CopyOnWriteArraySet<>();private static ConcurrentHashMap<Long,WebSocketServerUtil > webSocketMap  = new ConcurrentHashMap<>();private Long uId = null;@OnOpenpublic void onOpen(Session session, @PathParam("uId") Long uId){this.session = session;this.uId = uId;if(webSocketMap .containsKey(uId)){webSocketMap .remove(uId);webSocketMap .put(uId,this);}else{webSocketMap .put(uId,this);webSocketSet.add(this);}log.info("【websocket消息】有新的连接,总数:{}",webSocketMap.size());}@OnClosepublic void onClose(){if(webSocketMap.containsKey(uId)){webSocketMap.remove(uId);//从set中删除webSocketSet.remove(this);}log.info("【websocket消息】连接断开,总数:{}",webSocketSet.size());}@OnMessagepublic void onMessage(String message){log.info("【websocket消息】收到客户端发来的消息:{}",message);}public void sendMessage(String message){try {this.session.getBasicRemote().sendText(message);} catch (IOException e) {e.printStackTrace();}}/*** 发送自定义消息* */public static void sendInfo(String message,Long uId) throws Exception {//log.info("发送消息到:"+uId+",报文:"+message);if(webSocketMap.containsKey(uId)){webSocketMap.get(uId).sendMessage(message);}else{log.error("用户"+uId+",不在线!");throw new Exception("连接已关闭,请刷新页面后重试");}}
}

调用Util方法

        Long uId = new Long("1");Map msgMap = new HashMap();msgMap.put("step",1);msgMap.put("type",2);msgMap.put("msg","hello");WebSocketServerUtil.sendInfo(JsonUtil.toJson(msgMap),uId);

前端JS代码

/*** 初始化websocket连接*/
function initWebSocket() {let uId = 1;var websocket = null;if('WebSocket' in window) {websocket = new WebSocket("ws://localhost:8009/webSocket"+uId );} else {alert("该浏览器不支持websocket!");}websocket.onopen = function(event) {console.log("建立连接");websocket.send('Hello WebSockets!');}websocket.onclose = function(event) {console.log('连接关闭')reconnect(); //尝试重连websocket}//建立通信后,监听到后端的数据传递websocket.onmessage = function(event) {let data = JSON.parse(event.data);//业务处理....if(data.step == 1){alert(data.msg);}}websocket.onerror = function() {// notify.warn("websocket通信发生错误!");// initWebSocket()}window.onbeforeunload = function() {websocket.close();}
// 重连
function reconnect() {console.log("正在重连");// 进行重连setTimeout(function () {initWebSocket();}, 1000);
}

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

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

相关文章

【LeetCode刷题笔记】前缀树

208. 实现 Trie (前缀树) 解题思路: 1. 前缀树 Map实现 ,使用一个 Map<Character, Trie> 来存储 每个字符 对应的 若干子节点 ,在构造函数中初始化 根节点 root 为 当前对象实例 , 在 插入

技术分享 | 接口测试请求超时怎么办?

​ &#x1f4e2;专注于分享软件测试干货内容&#xff0c;欢迎点赞 &#x1f44d; 收藏 ⭐留言 &#x1f4dd; 如有错误敬请指正&#xff01;&#x1f4e2;交流讨论&#xff1a;欢迎加入我们一起学习&#xff01;&#x1f4e2;资源分享&#xff1a;耗时200小时精选的「软件测试…

【基础知识】大数据组件HBase简述

HBase是一个开源的、面向列&#xff08;Column-Oriented&#xff09;、适合存储海量非结构化数据或半结构化数据的、具备高可靠性、高性能、可灵活扩展伸缩的、支持实时数据读写的分布式存储系统。 只是面向列&#xff0c;不是列式存储 mysql vs hbase vs clickhouse HMaster …

Qt/C++视频监控Onvif工具/组播搜索/显示监控画面/图片参数调节/OSD管理/祖传原创

一、前言 能够写出简单易用而又不失功能强大的组件&#xff0c;一直是我的追求&#xff0c;简单主要体现在易用性&#xff0c;不能搞一些繁琐的流程和一些极难使用的API接口&#xff0c;或者一些看不懂的很难以理解的函数名称&#xff0c;一定是要越简单越好。功能强大主要体现…

【SpringMVC】REST(Representation State Transfer)ful开发

REST全称Representation State Transfer&#xff0c;表现形式状态转换 文章目录 1. 为什么提出了REST&#xff1f;2. RESTful入门案例案例代码修改请求方式修改成RESTful风格&#xff0c;并以POST方式提交 RESTful格式下传参RESTful入门案例总结RequestBody&#xff0c;Reques…

工业互联网:常用的MQTT客户端与Broker

背景 作为物联网终端数据上云协议事实上的标准&#xff0c;当涉及到 MQTT &#xff08;Message Queuing Telemetry Transport&#xff09;协议时&#xff0c;目前有许多不同的 Broker 和客户端工具可供选择。本文简要罗列下常见的 Broker 和客户端工具&#xff0c;以及可供测试…

锐捷ssh配置

配置实例 ssh-Server ssh-Server(config)#enable service ssh-server // 启用ssh服务 ssh-Server(config)#username admin privilege 15 password Test123456 // 设置ssh登陆的账户密码 ssh-Server(config)#line vty 0 4 ssh-Server(config-line)#transport input ssh …

【数据结构和算法】---栈和队列的互相实现

目录 一、用栈实现队列1.1初始化队列1.2模拟入队列1.3模拟出队列1.4取模拟的队列头元素1.5判断队列是否为空 二、用队列实现栈2.1初始化栈2.2模拟出栈2.3模拟入栈2.4取模拟的栈顶元素2.5判读栈是否为空 一、用栈实现队列 具体题目可以参考LeetCode232. 用栈实现队列 首先要想到…

matlab 点云最小二乘拟合空间直线(PCA法)

目录 一、算法原理二、代码实现三、结果展示本文由CSDN点云侠原创,原文链接。爬虫网站自重。如果你不是在点云侠的博客中看到该文章,那么此处便是不要脸的爬虫。 一、算法原理 见:matlab 点云最小二乘拟合空间直线。 二、代码实现 clc;clear; %% ----

IMX6Q平台下双通道LVDS屏幕linux驱动设备树调试笔记

一、 LVDS简单理解 LVDS粗略了解 LVDS Low-Voltage Differential Signaling 低电压差分信号&#xff0c;属于平衡传输信号。这种技术的核心是采用极低的电压摆幅高速差动传输数据&#xff0c;从而有以下特点&#xff1a;低功耗—低误码率—低串扰—低抖动—低辐射 良好的信号…

论文阅读——Flamingo

Flamingo: a Visual Language Model for Few-Shot Learning 模型建模了给定交织的图片或支视频的条件下文本y的最大似然&#xff1a; 1 Visual processing and the Perceiver Resampler Vision Encoder&#xff1a;from pixels to features。 预训练并且冻结的NFNet&#xff…

字符设备驱动开发-注册-设备文件创建

一、字符设备驱动 linux系统中一切皆文件 1、应用层&#xff1a; APP1 APP2 ... fd open("led驱动的文件"&#xff0c;O_RDWR); read(fd); write(); close(); 2、内核层&#xff1a; 对灯写一个驱动 led_driver.c driver_open(); driver_read(); driver_write(…