websocket入门及应用

websocket

When to use a HTTP call instead of a WebSocket (or HTTP 2.0)

WebSocket 是基于TCP/IP协议,独立于HTTP协议的通信协议。WebSocket 是双向通讯,有状态,客户端一(多)个与服务端一(多)双向实时响应(客户端 ⇄ 服务端)。WebSocket 是应用在浏览器的 Socket (是 Socket 模型接口的实现),Socket 是一个网络通信接口 (通信规范)。

WebSocket协议端口是80。WebSocket SSL协议端口是443。*Socket是TCP/IP协议的网络数据通讯接口(一种底层的通讯的方式)。image-20230827173621392

image-20230827180052083

引入依赖

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

定义配置类

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

定义controller

定义controller接口规范传输

public interface WebsocketHandler {void onOpen(Session session);void onClose(Session session);void onMessage(String message);
}

定义controller实现交互

package com.wnhz.wnmap.schedule.controller;import com.wnhz.wnmap.schedule.vo.MessageVo;
import com.wnhz.wnmap.schedule.common.util.JsonUtil;
import com.wnhz.wnmap.schedule.handler.WebsocketHandler;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Controller;import javax.websocket.OnClose;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.Objects;@ServerEndpoint("/ws/api")
@Slf4j
public class ScheduleController implements WebsocketHandler {private Session session;private int count;@OnOpen@Overridepublic void onOpen(Session session) {this.session = session;MessageVo webMessage = new MessageVo(++count, MessageVo.MessageType.WEBSOCKET_OPEN, "websocket连接成功...");String message = JsonUtil.toString(webMessage);this.sendMessage(message);log.debug("websocket建立成功.......");}@OnClose@Overridepublic void onClose(Session session) {this.session = session;MessageVo webMessage = new MessageVo(--count, MessageVo.MessageType.WEBSOCKET_OPEN, "websocket断开连接成功...");String message = JsonUtil.toString(webMessage);this.sendMessage(message);log.debug("websocket关闭成功.......");}@OnMessage@Overridepublic void onMessage(String message) {MessageVo messageVo = new MessageVo();messageVo.setType(MessageVo.MessageType.WEBSOCKET_MESSAGE);  //类型3指信息交互messageVo.setCount(count);messageVo.setMessage(message);String json = JsonUtil.toString(messageVo);this.sendMessage(json);log.debug("[websocket消息:]收到客户端发来的消息:{}", message);}private void sendMessage(String message) {try {log.debug("[websocket服务器返回信息:] {}", message);if(Objects.nonNull(this.session)){this.session.getBasicRemote().sendText(message);}} catch (IOException e) {e.printStackTrace();}}
}

vue+wesocket

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Websocket</title><script src="https://cdn.jsdelivr.net/npm/vue@2"></script>
</head>
<body><div id="app"><textarea>{{msg}}</textarea><hr/><input type="text" placeholder="请输入传输数据" v-model="sendTxt"><button @click="wsend">发送</button></div><script>new Vue({el: '#app',data() {return {websocket: null,msg: '',sendTxt: ''}},created() {this.init();},methods: {init: function () {this.websocket = new WebSocket('ws://localhost:15555/ws/api');this.websocket.onopen = this.wopen;this.websocket.onmessage = this.wMessage;this.websocket.onclose = this.wclose;},wopen: function () {console.log("socket连接成功.....")},wMessage: function (e) {console.log("接收到的信息: " + e.data )let data = eval("(" + e.data + ")"); //解析对象this.msg = data.message;},wclose: function () {console.log("websocket连接端口.....")},wsend: function () {console.log("发送新消息......" + this.sendTxt);this.websocket.send(this.sendTxt);}},destroyed() {this.websocket.onclose = this.close();}});</script></body>
</html>

image-20230827212823339

前后端交互案例

案例一

后端
public interface WebSocketHandler {void onOpen(Session session);void onClose();void onMessage(String message);
}
public class WebSocketServer implements WebsocketHandler {@OnOpen@Overridepublic void onOpen(Session session) {System.out.println("连接--->"+session);WebSocketUtil.put(session);log.debug("前端与后台建立连接:{}", this);}@OnClose@Overridepublic void close() {log.debug("前端已关闭连接:{}", this);//webSocketServers.remove(this);}@OnMessage@Overridepublic void onMessage(String message) {log.debug("接收到前端信息:{}", message);log.debug("---------向前端发送信息-----------------");//  sendMessage("[服务器:] 你好,信息从后台返回");}@RabbitListener(queues = "regist_simple_queue")public void registryUser(User user) throws Exception {System.out.println("消费--->"+user);//System.out.println("------------>"+WebSocketUtil.get());Thread.sleep(5000);WebSocketUtil.get().getBasicRemote().sendText(user.getUsername()+"已经注册成功^_^");}
}
package com.wnhz.vue.web.socket;import javax.websocket.Session;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.CopyOnWriteArraySet;public class WebSocketUtil {private static final CopyOnWriteArrayList<Session> sessions = new CopyOnWriteArrayList<>();public static void put(Session session){sessions.add(session);}public static int size(){return sessions.size();}public static Session get(){return sessions.get(0);}
}
前端
<!DOCTYPE HTML>
<html>
<head><meta charset="utf-8"><title>vue发送websocket-to springboot</title><link rel="stylesheet" href="https://unpkg.com/element-ui/lib/theme-chalk/index.css"><script src="https://cdn.jsdelivr.net/npm/vue@2"></script><script src="https://unpkg.com/axios/dist/axios.min.js"></script><script src="https://unpkg.com/element-ui/lib/index.js"></script></head>
<body><div id="app"><input type="text" v-model="book.title" placeholder="书名"><input type="text" v-model="book.author" placeholder="作者"><input type="text" v-model="book.price" placeholder="价格"><input type="text" v-model="book.category" placeholder="类别"><button >运行 WebSocket</button>
</div><script>new Vue({el: '#app',data() {return {book: {title: '',author: '',price: '',category: ''},websocketPath: 'ws://localhost:9090/mysocket',ws: null}},mounted() {this.ws = new WebSocket(this.websocketPath);this.ws.onopen = this.open;this.ws.onmessage = this.getMessage;this.ws.onclose = this.close;},methods: {open: function () {this.ws.send("发送数据");console.log("websocket连接成功...");},getMessage: function (event) {let received_msg = event.data;console.log("receive: "+ received_msg);this.$message({message: received_msg,type: 'success'});},close: function () {console.log("websocket连接已经关闭")}},destroyed() {this.ws.onclose = this.close();}});
</script></body>
</html>

案例二

前端
<template><div><el-input v-model="msg" placeholder="请问您还有什么问题?"></el-input><el-button type="button" @click="wssend">发送给客服</el-button></div>
</template><script>
export default {data() {return {websocket: null,msg: ''};},created() {this.websocket = new WebSocket('ws://localhost:9999/mysocket');this.websocket.onopen = this.wsopen;this.websocket.onclose = this.wsclose;this.websocket.onmessage = this.wsmessage;},methods: {wsopen() {console.log("websocket连接成功.....")},wsclose() {console.log("websocket关闭成功.....")},wsmessage(event) {//获取后台交互console.log("===>" + event.data);this.$notify({title: '来自客服',message: event.data,duration: 2000});      },wssend() {this.websocket.send(this.msg);}}
}
</script>
后台
package com.wnhz.websocket.ws;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.ServerEndpoint;
import java.io.IOException;@Component
@ServerEndpoint("/mysocket")
@Slf4j
public class WebSocketController {/*** 建立websocket连接*/@OnOpenpublic void onOpen(Session session) throws IOException {log.debug("建立websocket连接成功,sessionId:{}",session.getId());session.getBasicRemote().sendText("[from server:]"+"I'm fine!!!");}@OnClosepublic void onClose(Session session) throws IOException {log.debug("websocket连接断开,sessionId:{}",session.getId());session.close();}@OnMessagepublic void sendMessage(Session session,String message) throws IOException {log.debug("[from web:]{}",message);if("你好".equals(message)){session.getBasicRemote().sendText("亲,您好,有什么能为您服务的^_^");}if("退货".equals(message)){session.getBasicRemote().sendText("对不起,客服繁忙中,请稍后再咨询");}}
}

应用场景

1.社交订阅

对社交类的应用的一个裨益之处就是能够即时的知道你的朋友正在做什么。虽然听起来有点可怕,但是我们都喜欢这样做。你不会想要在数分钟之后才能知道一个家庭成员在馅饼制作大赛获胜或者一个朋友订婚的消息。你是在线的,所以你的订阅的更新应该是实时的。

2.多玩家游戏

网络正在迅速转变为游戏平台。在不使用插件(我指的是Flash)的情况下,网络开发者现在可以在浏览器中实现和体验高性能的游戏。无论你是在处理DOM元素、CSS动画,HTML5的canvas或者尝试使用WebGL,玩家之间的互动效率是至关重要的。我不想在我扣动扳机之后,我的对手却已经移动位置。

3.协同编辑/编程

我们生活在分布式开发团队的时代。平时使用一个文档的副本就满足工作需求了,但是你最终需要有一个方式来合并所有的编辑副本。版本控制系统,比如Git能够帮助处理某些文件,但是当Git发现一个它不能解决的冲突时,你仍然需要去跟踪人们的修改历史。通过一个协同解决方案,比如WebSocket,我们能够工作在同一个文档,从而省去所有的合并版本。这样会很容易看出谁在编辑什么或者你在和谁同时在修改文档的同一部分。

4.点击流数据

分析用户与你网站的互动是提升你的网站的关键。HTTP的开销让我们只能优先考虑和收集最重要的数据部分。然后,经过六个月的线下分析,我们意识到我们应该收集一个不同的判断标准——一个看起来不是那么重要但是现在却影响了一个关键的决定。与HTTP请求的开销方式相比,使用Websocket,你可以由客户端发送不受限制的数据。想要在除页面加载之外跟踪鼠标的移动?只需要通过WebSocket连接发送这些数据到服务器,并存储在你喜欢的NoSQL数据库中就可以了(MongoDB是适合记录这样的事件的)。现在你可以通过回放用户在页面的动作来清楚的知道发生了什么。

5.股票基金报价

金融界瞬息万变——几乎是每毫秒都在变化。我们人类的大脑不能持续以那样的速度处理那么多的数据,所以我们写了一些算法来帮我们处理这些事情。虽然你不一定是在处理高频的交易,但是,过时的信息也只能导致损失。当你有一个显示盘来跟踪你感兴趣的公司时,你肯定想要随时知道他们的价值,而不是10秒前的数据。使用WebSocket可以流式更新这些数据变化而不需要等待。

6.体育实况更新

现在我们开始讨论一个让人们激情澎湃的愚蠢的东西——体育。我不是运动爱好者,但是我知道运动迷们想要什么。当爱国者在打比赛的时候,我的妹夫将会沉浸于这场比赛中而不能自拔。那是一种疯狂痴迷的状态,完全发自内心的。我虽然不理解这个,但是我敬佩他们与运动之间的这种强烈的联系,所以,最后我能做的就是给他的体验中降低延迟。如果你在你的网站应用中包含了体育新闻,WebSocket能够助力你的用户获得实时的更新。

7.多媒体聊天

视频会议并不能代替和真人相见,但当你不能在同一个屋子里见到你谈话的对象时,视频会议是个不错的选择。尽管视频会议私有化做的“不错”,但其使用还是很繁琐。我可是开放式网络的粉丝,所以用WebSockets getUserMedia API和HTML5音视频元素明显是个不错的选择。WebRTC的出现顺理成章的成为我刚才概括的组合体,它看起来很有希望,但其缺乏目前浏览器的支持,所以就取消了它成为候选人的资格。

8.基于位置的应用

越来越多的开发者借用移动设备的GPS功能来实现他们基于位置的网络应用。如果你一直记录用户的位置(比如运行应用来记录运动轨迹),你可以收集到更加细致化的数据。如果你想实时的更新网络数据仪表盘(可以说是一个监视运动员的教练),HTTP协议显得有些笨拙。借用WebSocket TCP链接可以让数据飞起来。

9.在线教育

上学花费越来越贵了,但互联网变得更快和更便宜。在线教育是学习的不错方式,尤其是你可以和老师以及其他同学一起交流。很自然,WebSockets是个不错的选择,可以多媒体聊天、文字聊天以及其它优势如与别人合作一起在公共数字黑板上画画…

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

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

相关文章

代码随想录刷题第43天

第一题是最后一块石头的重量IIhttps://leetcode.cn/problems/last-stone-weight-ii/&#xff0c;没啥思路&#xff0c;直接上题解了。本题可以看作将一堆石头尽可能分成两份重量相似的石头&#xff0c;于是问题转化为如何合理取石头&#xff0c;使其装满容量为石头总重量一半的…

【AI Agent系列】【MetaGPT多智能体学习】0. 环境准备 - 升级MetaGPT 0.7.2版本及遇到的坑

之前跟着《MetaGPT智能体开发入门课程》学了一些MetaGPT的知识和实践&#xff0c;主要关注在MetaGPT入门和单智能体部分&#xff08;系列文章附在文末&#xff0c;感兴趣的可以看下&#xff09;。现在新的教程来了&#xff0c;新教程主要关注多智能体部分。 本系列文章跟随《M…

五种主流数据库:常用字符函数

SQL 字符函数用于字符数据的处理&#xff0c;例如字符串的拼接、大小写转换、子串的查找和替换等。 本文比较五种主流数据库常用数值函数的实现和差异&#xff0c;包括 MySQL、Oracle、SQL Server、PostgreSQL 以及 SQLite。 字符函数函数功能MySQLOracleSQL ServerPostgreSQ…

Wagtail安装运行并结合内网穿透实现公网访问本地网站界面

文章目录 前言1. 安装并运行Wagtail1.1 创建并激活虚拟环境 2. 安装cpolar内网穿透工具3. 实现Wagtail公网访问4. 固定的Wagtail公网地址 正文开始前给大家推荐个网站&#xff0c;前些天发现了一个巨牛的 人工智能学习网站&#xff0c; 通俗易懂&#xff0c;风趣幽默&#xf…

C++Lambda表达式介绍

C11中引入了Lambda表达式&#xff0c;Lambda表达式是一种匿名函数&#xff0c;它可以在需要函数的地方直接定义和使用&#xff0c;而无需显式地定义一个函数。 lambda表达式 Lambda表达式语法定义 [capture-list](parameters) -> return-type { statement } capture-lis…

cmake build

cmake -H. -Bbuild 这是使用 CMake 的命令行工具来配置项目的命令。具体来说&#xff1a; cmake 是 CMake 的命令行工具。-H. 表示 CMakeLists.txt 文件所在的源代码目录是当前目录 (.)。这个选项指定了 CMakeLists.txt 所在的路径&#xff0c;这样 CMake 就知道在哪里找到项目…

SQL Developer 小贴士:PL/SQL语法分析

对于SQL或PL/SQL中的语法错误和警告&#xff0c;SQL Developer可以用不同颜色的下划波浪线显示。 启用语法分析&#xff0c;可以用菜单Tool>Preferences>Code Editor>Completion Insight>Enable Semantic Analysis Info Tips 例如&#xff0c;以下的代码中&…

blender bvh显示关节名称

导入bvh&#xff0c;菜单选择布局&#xff0c;右边出现属性窗口&#xff0c; 在下图红色框依次点击选中&#xff0c;就可以查看bvh关节名称了。

微服务架构设计 | 如何设计高性能系统

一、引言 互联网时代&#xff0c;业务系统的主要特点是用户多、请求量大。尤其在中国这样拥有庞大用户基数的环境下&#xff0c;不用说阿里巴巴、京东这类需要满足双十一大促时每秒几万甚至几十万订单的系统&#xff0c;即使是一些垂直领域的业务系统&#xff08;如三甲医院的…

自考《计算机网络原理》考前冲刺

常考选择填空 1、计算机网络的定义&#xff1a;计算机网络是互连的、自治的计算机的集合。 2、协议的定义&#xff1a;协议是网络通信实体之间在数据交换过程中需要遵循的规则或约定 3、协议的3个要素 (1) 语法&#xff1a;定义实体之间交换信息的格式与结构&#xff0c;或…

设计模式六:策略模式

1、策略模式 策略模式定义了一系列的算法&#xff0c;并将每一个算法封装起来&#xff0c;使每个算法可以相互替代&#xff0c;使算法本身和使用算法的客户端分割开来&#xff0c;相互独立。 策略模式的角色&#xff1a; 策略接口角色IStrategy&#xff1a;用来约束一系列具体…

第一次开机开机动画结束后闪白屏

开机动画结束会闪下白屏&#xff0c;再进入launcher 思路 : 分析下从开机动画结束到launcher起来之间的流程步骤 从ZygoteInit.java开始分析 &#xff1a; SystemServer起来后会启动一些核心服务 attachApplication方法中主要创建了Application和Activity 接下里RootActivityC…

快速搭建网站原型!8款网站原型软件推荐

现在&#xff0c;基于云的软件已经逐渐成为主流&#xff0c;网站原型设计工具也不例外。与桌面版本相比&#xff0c;在线原型工具具有独特的优势&#xff0c;无论您使用Linux&#xff0c;Mac 或者Windows&#xff0c;都不需要安装就可以使用这些工具。下面小编就为大家推荐8款非…

c++入门学习⑧——模板

目录 前言 基本介绍 什么是模板&#xff1f; 作用 特点 分类 函数模板 语法 使用方式 注意事项 函数模板和普通函数区别 普通函数和函数模板的调用规则 局限性 类模板 语法 类模板的成员函数创建时机 类模板实例化对象 类模板实例化对象做函数参数 类模板成…

Node.js_基础知识(fs模块 - 文件操作)

写入 文件操作 流式写入:fs.createWriteStream(path[, options]) 可以减少打开关闭文件的次数适用于:大文件写入、频繁写入参数说明: path:文件路径文件夹操作: 调用mkdir方法:fs.mkdir(./a/b/c, err => {}) 递归创建文件夹:加参数recursive fs.mkdir(./a/b/c, {recu…

普中51单片机学习(LCD1602)

LCD1602 1602液晶也叫1602字符型液晶&#xff0c;它是一种专门用来显示字母、数字、符号的点阵型液晶模块。它是由若干个5x7或者5x10的点阵字符位组成&#xff0c;每个点阵字符位都可以用显示一个字符&#xff0c;每位之间有一个点距的间隔&#xff0c;每行之间也有间隔&#…

代码随想录算法训练营29期|day60 任务以及具体安排

第九章 动态规划part17 647. 回文子串 class Solution {public int countSubstrings(String s) {char[] chars s.toCharArray();int len chars.length;boolean[][] dp new boolean[len][len];int result 0;for (int i len - 1; i > 0; i--) {for (int j i; j < le…

【Spring连载】使用Spring Data的Repositories----存储库查询返回类型

【Spring连载】使用Spring Data的Repositories----存储库查询返回类型 支持的查询返回类型 支持的查询返回类型 下表列出了Spring Data存储库通常支持的返回类型。但是&#xff0c;有关支持的返回类型的确切列表&#xff0c;请参阅特定存储的文档&#xff0c;因为此处列出的某…

C++面试:死锁的危害、出现原因、解决方法

目录 死锁的危害 死锁出现的原因 死锁的解决方法 死锁是计算机科学中一个非常重要的概念&#xff0c;特别是在多线程、并发编程以及数据库管理系统等领域中。下面是关于死锁的危害、出现原因和解决方法的基础概述&#xff1a; 死锁的危害 资源浪费&#xff1a;死锁导致系统…

设计模式:模版模式

模板模式&#xff08;Template Pattern&#xff09;是一种行为型设计模式&#xff0c;它定义了一个操作中的算法骨架&#xff0c;将一些步骤的具体实现延迟到子类中。模板模式使得子类可以在不改变算法结构的情况下重新定义算法的某些步骤。 在模板模式中&#xff0c;将算法的…