如何用单线程和定时任务分别实现WebSocket聊天室
发表于:2024-11-22 作者:千家信息网编辑
千家信息网最后更新 2024年11月22日,这篇文章主要讲解了"如何用单线程和定时任务分别实现WebSocket聊天室",文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习"如何用单线程和定时任务分别实现
千家信息网最后更新 2024年11月22日如何用单线程和定时任务分别实现WebSocket聊天室
这篇文章主要讲解了"如何用单线程和定时任务分别实现WebSocket聊天室",文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习"如何用单线程和定时任务分别实现WebSocket聊天室"吧!
1.需求场景
多媒体实时聊天
股票基金等数据报价
位置定位
社交订阅
数据库更新,前端实时显示
要实现这种实时性较强的功能,以前经常采用的方法:轮询和Comet技术
轮询:要求客户端已设定的时间间隔周期性地向服务器端发送请求,频繁查询数据是否变动。缺点:过多不必要的请求,浪费流量和服务器资源。
Comet技术:可以分为长轮询和流技术。长轮询改进上述轮询,减少无用的请求,设定过期时间,当数据过期后才会向服务器端发送请求,适合数据改动不频繁的场景;流技术是指客户端通过一个隐藏的窗口与服务器建立一个HTTP长连接,不断更新连接状态保持连接不断开。
总结:都是基于请求-应答模式,不算真正意义上的实时技术,每一次请求应答,都要消耗一定流量。
2.WebSocket原理
WebSocket协议基于TCP协议实现,工作流程是这 样的:浏览器通过JavaScript向服务端发出建立WebSocket连接的请求,在WebSocket连接建立成功后,客户端和服务端就可以通过 TCP连接传输数据。因为WebSocket连接本质上是TCP连接,不需要每次传输都带上重复的头部数据, 其优点:
通过第一次Http Request第一次建立连接之后,之后的数据交换都不要再重新发送Http Request,节省了宽带资源
WebSocket协议是双向通信协议,既可以发送又可以接受
多路复用即多个不同的URL可以复用同一个Websocket连接
3.打造Websocket聊天室
温馨提示:基于IAEA+SpringBoot+Gradle开发,得益于SpringBoot提供的自动配置,只需要通过简单注解@ServerEndpoint就能创建WebSocket服务端,再通过简单的回调函数就能完成WebSocket服务端的编写!
build.gadle
//spring-boot-starter-websocket的依赖springboot的高级组件会自动引用基础的组件, // 像spring-boot-starter-websocket就引入了spring-boot-starter-web和spring-boot-starter compile group: 'org.springframework.boot', name: 'spring-boot-starter-websocket', version: '2.1.6.RELEASE' //thymeleaf compile group: 'org.springframework.boot', name: 'spring-boot-starter-thymeleaf', version: '2.1.6.RELEASE'
创建一个WebSocketConfig
package com.example.SmartHome.config;import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import org.springframework.stereotype.Component;import org.springframework.web.socket.server.standard.ServerEndpointExporter;/* *@Description: 自动注册使用了@ServerEndpoint注解声明的Websocket endpoint *@ClassName: WebSocketConfig *@Author: zzq *@Date: 2019/7/7 11:01 *@Version: 1.0 */@Configuration@Component@ConditionalOnWebApplicationpublic class WebSocketConfig { /** * 自动注册使用了@ServerEndpoint注解声明的Websocket endpoint */ @Bean public ServerEndpointExporter serverEndpointExporter() { return new ServerEndpointExporter(); }}
提醒:ServerEndpointExporter 是由Spring官方提供的标准实现,用于扫描ServerEndpointConfig配置类和@ServerEndpoint注解实例。使用规则:1.如果使用默认的嵌入式容器 比如Tomcat 则必须手工在上下文提供ServerEndpointExporter。2. 如果使用外部容器部署war包,则不要提供提供ServerEndpointExporter,因为此时SpringBoot默认将扫描服务端的行为交给外部容器处理。
创建WebSocket服务器
核心思路:① 通过注解@ServerEndpoint来声明实例化WebSocket服务端。② 通过注解@OnOpen、@OnMessage、@OnClose、@OnError 来声明回调函数。
事件类型 注解 事件描述 open @OnOpen 当打开连接后触发 message @OnMessage 当接受客户端消息时触发 error @OnError 当通信异常时触发 close @OnClose 当连接关闭时触发 package com.example.SmartHome.server;import org.springframework.stereotype.Component;import javax.websocket.*;import javax.websocket.server.ServerEndpoint;import java.io.IOException;import java.util.concurrent.CopyOnWriteArraySet;/* *@Description: WebSocketServer服务器端 *@ClassName: WebSocketServer *@Author: zzq *@Date: 2019/7/3 17:05 *@Version: 1.0 *///ServerEndpoint这个bean会自动注册使用了@ServerEndpoint注解声明的Websocket endpoint。// 要注意,如果使用独立的servlet容器,而不是直接使用springboot的内置容器,// 就不要注入ServerEndpointExporter,// 因为它将由容器自己提供和管理。/** * @ServerEndpoint 注解是一个类层次的注解,它的功能主要是将目前的类定义成一个websocket服务器端, * 注解的值将被用于监听用户连接的终端访问URL地址,客户端可以通过这个URL来连接到WebSocket服务器端 */@ServerEndpoint("/websocket")@Component //它的主要作用就是将这个监听器纳入到Spring容器中进行管理public class WebSocket {// MyThread thread1=new MyThread();// Thread thread =new Thread(thread1); //每个客户端都会有相应的session,服务端可以发送相关消息 private Session session; public static int onlineCount = 0; //J.U.C包下线程安全的类,主要用来存放每个客户端对应的webSocket连接 private static CopyOnWriteArraySet
copyOnWriteArraySet = new CopyOnWriteArraySet (); /** * @Name:onOpen * @Description:打开连接。进入页面后会自动发请求到此进行连接 */ @OnOpen public void onOpen(Session session) throws IOException { this.session = session; copyOnWriteArraySet.add(this); addOnlineCount(); System.out.println("websocket有新的连接, 总数:" + getOnlineCount()); sendMessage("成功连接"); } /** * @Name:onClose * @Description:用户关闭页面,即关闭连接 */ @OnClose public void onClose() { copyOnWriteArraySet.remove(this); shortOnlineCount(); System.out.println("websocket连接断开, 总数:" + getOnlineCount()); } /** * @Name:onMessage * @Description:收到客户端消息后调用的方法 */ @OnMessage public void onMessage(String message,Session session) throws IOException { System.out.println("websocket收到客户端发来的消息:" + message); for(WebSocket webSocket:copyOnWriteArraySet){ webSocket.sendMessage(message); } } /** * @Name:onError * @Description:出现错误 */ @OnError public void onError(Session session, Throwable error) { System.out.println("发生错误:" + error.getMessage() + "; sessionId:" + session.getId()); error.printStackTrace(); } public void sendMessage(String message) throws IOException { this.session.getBasicRemote().sendText(message); // this.session.getAsyncRemote().sendText(message); } public void sendMessage(Object object) { //遍历客户端 for (WebSocket webSocket : copyOnWriteArraySet) { System.out.println("websocket广播消息:" + object.toString()); try { //服务器主动推送 webSocket.session.getBasicRemote().sendObject(object); } catch (Exception e) { e.printStackTrace(); } } } /** * @Name:sendMessage * @Description:用于发送给客户端消息(群发) */ public static void sendInfo(String message) { //遍历客户端 for (WebSocket webSocket : copyOnWriteArraySet) { System.out.println("websocket广播消息:" + message); try { //服务器主动推送 webSocket.session.getBasicRemote().sendText(message); } catch (Exception e) { e.printStackTrace(); } } } /** * @Name:sendMessage * @Description:用于发送给指定客户端消息 */ public void sendMessage(String sessionId, String message) throws IOException { Session session = null; WebSocket tempWebSocket = null; for (WebSocket webSocket : copyOnWriteArraySet) { if (webSocket.session.getId().equals(sessionId)) { tempWebSocket = webSocket; session = webSocket.session; break; } } if (session != null) { tempWebSocket.session.getBasicRemote().sendText(message); } else { System.out.println("没有找到你指定ID的会话:{}" + "; sessionId:" + sessionId); } } public static synchronized int getOnlineCount(){ return onlineCount; } public static synchronized void addOnlineCount(){ WebSocket.onlineCount++; } public static synchronized void shortOnlineCount(){ WebSocket.onlineCount--; }} 4.Controller类
package com.example.SmartHome.controller;import org.springframework.stereotype.Controller;import org.springframework.web.bind.annotation.RequestMapping;/* *@Description: TODO *@ClassName: ChatController *@Author: zzq *@Date: 2019/7/9 16:56 *@Version: 1.0 */@Controllerpublic class ChatController { @RequestMapping("/websocket") public String init() { return "websocket.html"; }}
5.前端代码
My WebSocket Test Welcome
6.结果展示
服务端:
感谢各位的阅读,以上就是"如何用单线程和定时任务分别实现WebSocket聊天室"的内容了,经过本文的学习后,相信大家对如何用单线程和定时任务分别实现WebSocket聊天室这一问题有了更深刻的体会,具体使用情况还需要大家实践验证。这里是,小编将为大家推送更多相关知识点的文章,欢迎关注!
服务
客户
客户端
注解
消息
服务器
数据
容器
方法
线程
聊天室
技术
任务
实时
主动
成功
事件
错误
学习
推送
数据库的安全要保护哪些东西
数据库安全各自的含义是什么
生产安全数据库录入
数据库的安全性及管理
数据库安全策略包含哪些
海淀数据库安全审计系统
建立农村房屋安全信息数据库
易用的数据库客户端支持安全管理
连接数据库失败ssl安全错误
数据库的锁怎样保障安全
网络安全防护物理层
丽江服务器显卡加盟
浪潮金融软件开发语言
神通数据库安装
做软件开发外包在哪接单
镜湖网络安全考试scsa认证
动态ip能做服务器吗
贺卡制作软件开发
数据库文件打开的四种方式
网络安全宣传品牌
刑侦大队数据库
末日觉醒连不上单机服务器
DW怎么查询数据库的东西
郑州统计年鉴知网数据库
无线网络技术使用的介质是
计数机网络技术专业学科目
软件开发与软件测试职业能力要求
网络安全管理警察公务员
网络安全设备市场分析
dell服务器找不到硬盘
太仓管理软件开发推荐咨询
数据库一般都用什么字符集
做软件开发外包在哪接单
信息网络安全管控平台 方案
佛山互联网络科技
网络安全大赛的感想
直播平台服务器安装
广州服务器pdu电源定制
数据库开发岗位
java软件开发电子书