赞
踩
在我之前的一篇文章当中写到了websocket的实时刷新,但是有个问题没有解决,就是长时间没有数据的时候,这个连接就会自动断开,然后再次进行连接的话,需要再次进行连接。如果加入心跳机制的话,10秒钟客户端向服务端发送数据,服务端接收到数据,发条消息,告诉客户端我还在,客户端接收到消息,知道我们还是连接的状态,就没有必要再进行连接。如果客户端发送的消息,服务端没有对这个消息进行响应,则说明已经断开连接,则需要重新连接。
服务端代码如下:
package cn.lsmsp.alarm.snmp.config; import com.alibaba.fastjson.JSON; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Component; import javax.websocket.*; import javax.websocket.server.PathParam; import javax.websocket.server.ServerEndpoint; import java.time.LocalDateTime; import java.util.HashMap; import java.util.Map; import java.util.concurrent.CopyOnWriteArraySet; @Component @ServerEndpoint("/websocket/{shopId}") //此注解相当于设置访问URL public class WebSocket { private Logger logger = LoggerFactory.getLogger(WebSocket.class); private Session session; private static CopyOnWriteArraySet<WebSocket> webSockets = new CopyOnWriteArraySet<>(); private static Map<String, Session> sessionPool = new HashMap<String, Session>(); @OnOpen public void onOpen(Session session, @PathParam(value = "shopId") String shopId) throws InterruptedException { this.session = session; webSockets.add(this); // sessionPool.put(shopId, session); // System.out.println("【websocket消息】有新的连接,总数为:"+webSockets.size()); System.out.println("【websocket消息】有新的连接啦!!!"+LocalDateTime.now()); // webSocketXdxService.xdxTest(shopId); } @OnClose public void onClose(Session session) { try { webSockets.remove(this); session.close(); System.out.println("【websocket消息】连接断开,总数为:" + webSockets.size()); } catch (Exception e) { e.printStackTrace(); } } @OnMessage public void onMessage(String message) { logger.info("【websocket消息】收到客户端消息:" + message); Map<String, Object> maps = new HashMap<>(); maps.put("type", message); this.sendAllMessage(JSON.toJSONString(maps)); } // 此为广播消息 public void sendAllMessage(String message) { for (WebSocket webSocket : webSockets) { System.out.println("【websocket消息】广播消息:" + message); try { webSocket.session.getAsyncRemote().sendText(message); } catch (Exception e) { e.printStackTrace(); } } } // 此为单点消息 (发送文本) public void sendTextMessage(String shopId, String message) { Session session = sessionPool.get(shopId); if (session != null) { try { session.getBasicRemote().sendText(message); } catch (Exception e) { e.printStackTrace(); } } } // 此为单点消息 (发送对象) public void sendObjMessage(String shopId, Object message) { Session session = sessionPool.get(shopId); if (session != null) { try { session.getAsyncRemote().sendObject(message); } catch (Exception e) { e.printStackTrace(); } } } }
相对于上次,结合我这边的业务进行了调整,删除了session的存储,就变成了一个用户多个聊天窗口的那种概念。
客户端代码如下:
<template> <div> <h1>测试webSocket</h1> <div id ="aaa" style="height: 300px; overflow-y: scroll; background: #333; color: #aaa; padding: 10px;"></div> </div> </template> <script> var that; export default { data(){ return { data:0, timeout: 30 * 1000,//30秒一次心跳 timeoutObj: null,//心跳心跳倒计时 serverTimeoutObj: null,//心跳倒计时 timeoutnum: null,//断开 重连倒计时 websocket: null, } }, created() { // 页面创建生命周期函数 that = this; that.initWebSocket() }, destroyed: function () { // 离开页面生命周期函数 that.websocketclose(); }, methods: { initWebSocket: function () { // WebSocket与普通的请求所用协议有所不同,ws等同于http,wss等同于https that.websocket = new WebSocket("wss://127.0.0.1:9231/kh_snmptrap/websocket/lsmsp"); that.websocket.onopen = that.websocketonopen; that.websocket.onerror = that.websocketonerror; that.websocket.onmessage = that.setOnmessageMessage; that.websocket.onclose = that.websocketclose; // 监听窗口关闭事件,当窗口关闭时,主动去关闭websocket连接,防止连接还没断开就关闭窗口,server端会抛异常。 // window.onbeforeunload = that.onbeforeunload }, reconnect: function () { // 重新连接 if(that.lockReconnect) return; that.lockReconnect = true; //没连接上会一直重连,设置延迟避免请求过多 that.timeoutnum && clearTimeout(that.timeoutnum); that.timeoutnum = setTimeout(() => { //新连接 that.initWebSocket(); that.lockReconnect = false; }, 5000); }, reset: function () { // 重置心跳 // 清除时间 clearTimeout(that.timeoutObj); clearTimeout(that.serverTimeoutObj); // 重启心跳 that.start(); }, start: function () { // 开启心跳 that.timeoutObj && clearTimeout(that.timeoutObj); that.serverTimeoutObj && clearTimeout(that.serverTimeoutObj); that.timeoutObj = setTimeout(() => { // 这里发送一个心跳,后端收到后,返回一个心跳消息, if (that.websocket && that.websocket.readyState == 1) { // 如果连接正常 that.websocketsend('heartbeat'); } else { // 否则重连 that.reconnect(); } that.serverTimeoutObj = setTimeout(() => { //超时关闭 that.websocket.close(); }, that.timeout); }, that.timeout) }, setOnmessageMessage: function(event) { let obj = JSON.parse(event.data); // console.log("obj",obj) switch(obj.type) { case 'heartbeat': //收到服务器信息,心跳重置 that.reset(); break; case 'sendMessage': that.data = obj.data console.log("接收到的服务器消息:",JSON.stringify(obj.data,null,4)) document.getElementById('aaa').innerHTML=JSON.stringify(obj.data,null,4) } }, websocketonopen: function () { //开启心跳 that.start(); console.log("WebSocket连接成功!!!"+new Date()+"----"+that.websocket.readyState); }, websocketonerror: function (e) { console.log("WebSocket连接发生错误" + e); }, websocketonmessage: function (e) { console.log(e.data); // console.log(e); document.getElementById('aaa').innerHTML=e.data }, websocketclose: function (e) { that.websocket.close(); console.log("connection closed "); }, websocketsend(messsage) { that.websocket.send(messsage) }, closeWebSocket() { // 关闭websocket that.websocket.close() } } } </script> <style > </style>
相对于删上次,加入了心跳的时间。这样的话客户端会收到两种类型的数据,heartbeat和sendMessage,便于区别哪个是心跳数据,哪个是发送的数据。还有一点,我这里是https的请求,如果你是http请求的话,把wss://127.0.0.1:9231改为ws://127.0.0.1:9231。其它想知道的,参考我之前的一篇文章:springboot websocket 实时刷新(亲测可用版)
赞
踩
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。