本篇內(nèi)容主要講解“分布式下的WebSocket解決方案是什么”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實用性強。下面就讓小編來帶大家學習“分布式下的WebSocket解決方案是什么”吧!
創(chuàng)新互聯(lián)公司堅持“要么做到,要么別承諾”的工作理念,服務領域包括:網(wǎng)站制作、成都網(wǎng)站設計、企業(yè)官網(wǎng)、英文網(wǎng)站、手機端網(wǎng)站、網(wǎng)站推廣等服務,滿足客戶于互聯(lián)網(wǎng)時代的雙塔網(wǎng)站設計、移動媒體設計的需求,幫助企業(yè)找到有效的互聯(lián)網(wǎng)解決方案。努力成為您成熟可靠的網(wǎng)絡建設合作伙伴!
在介紹分布式集群之前,我們先來看一下王子的WebSocket代碼實現(xiàn),先來看java后端代碼如下:
import javax.websocket.*; import javax.websocket.server.PathParam; import javax.websocket.server.ServerEndpoint; import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONObject;import java.io.IOException; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; @ServerEndpoint("/webSocket/{key}") public class WebSocket { private static int onlineCount = 0; /** * 存儲連接的客戶端 */ private static Mapclients = new ConcurrentHashMap (); private Session session; /** * 發(fā)送的目標科室code */ private String key; @OnOpen public void onOpen(@PathParam("key") String key, Session session) throws IOException { this.key = key; this.session = session; if (!clients.containsKey(key)) { addOnlineCount(); } clients.put(key, this); Log.info(key+"已連接消息服務!"); } @OnClose public void onClose() throws IOException { clients.remove(key); subOnlineCount(); } @OnMessage public void onMessage(String message) throws IOException { if(message.equals("ping")){ return ; } JSONObject jsonTo = JSON.parseObject(message); String mes = (String) jsonTo.get("message"); if (!jsonTo.get("to").equals("All")){ sendMessageTo(mes, jsonTo.get("to").toString()); }else{ sendMessageAll(mes); } } @OnError public void onError(Session session, Throwable error) { error.printStackTrace(); } private void sendMessageTo(String message, String To) throws IOException { for (WebSocket item : clients.values()) { if (item.key.contains(To) ) item.session.getAsyncRemote().sendText(message); } } private void sendMessageAll(String message) throws IOException { for (WebSocket item : clients.values()) { item.session.getAsyncRemote().sendText(message); } } public static synchronized int getOnlineCount() { return onlineCount; } public static synchronized void addOnlineCount() { WebSocket.onlineCount++; } public static synchronized void subOnlineCount() { WebSocket.onlineCount--; } public static synchronized Map getClients() { return clients; }}
示例代碼中并沒有使用Spring,用的是原生的java web編寫的,簡單和大家介紹一下里面的方法。
onOpen:在客戶端與WebSocket服務連接時觸發(fā)方法執(zhí)行
onClose:在客戶端與WebSocket連接斷開的時候觸發(fā)執(zhí)行
onMessage:在接收到客戶端發(fā)送的消息時觸發(fā)執(zhí)行
onError:在發(fā)生錯誤時觸發(fā)執(zhí)行
可以看到,在onMessage方法中,我們直接根據(jù)客戶端發(fā)送的消息,進行消息的轉(zhuǎn)發(fā)功能,這樣在單體消息服務中是沒有問題的。
再來看一下js代碼
var host = document.location.host; // 獲得當前登錄科室 var deptCodes='${sessionScope.$UserContext.departmentID}'; deptCodes=deptCodes.replace(/[\[|\]|\s]+/g, ""); var key = '${sessionScope.$UserContext.userID}'+deptCodes; var lockReconnect = false; //避免ws重復連接 var ws = null; // 判斷當前瀏覽器是否支持WebSocket var wsUrl = 'ws://' + host + '/webSocket/'+ key; createWebSocket(wsUrl); //連接ws function createWebSocket(url) { try{ if('WebSocket' in window){ ws = new WebSocket(url); }else if('MozWebSocket' in window){ ws = new MozWebSocket(url); }else{ layer.alert("您的瀏覽器不支持websocket協(xié)議,建議使用新版谷歌、火狐等瀏覽器,請勿使用IE10以下瀏覽器,360瀏覽器請使用極速模式,不要使用兼容模式!"); } initEventHandle(); }catch(e){ reconnect(url); console.log(e); } } function initEventHandle() { ws.onclose = function () { reconnect(wsUrl); console.log("llws連接關閉!"+new Date().toUTCString()); }; ws.onerror = function () { reconnect(wsUrl); console.log("llws連接錯誤!"); }; ws.onopen = function () { heartCheck.reset().start(); //心跳檢測重置 console.log("llws連接成功!"+new Date().toUTCString()); }; ws.onmessage = function (event) { //如果獲取到消息,心跳檢測重置 heartCheck.reset().start(); //拿到任何消息都說明當前連接是正常的//接收到消息實際業(yè)務處理 ... }; } // 監(jiān)聽窗口關閉事件,當窗口關閉時,主動去關閉websocket連接,防止連接還沒斷開就關閉窗口,server端會拋異常。 window.onbeforeunload = function() { ws.close(); } function reconnect(url) { if(lockReconnect) return; lockReconnect = true; setTimeout(function () { //沒連接上會一直重連,設置延遲避免請求過多 createWebSocket(url); lockReconnect = false; }, 2000); } //心跳檢測 var heartCheck = { timeout: 300000, //5分鐘發(fā)一次心跳 timeoutObj: null, serverTimeoutObj: null, reset: function(){ clearTimeout(this.timeoutObj); clearTimeout(this.serverTimeoutObj); return this; }, start: function(){ var self = this; this.timeoutObj = setTimeout(function(){ //這里發(fā)送一個心跳,后端收到后,返回一個心跳消息, //onmessage拿到返回的心跳就說明連接正常 ws.send("ping"); console.log("ping!") self.serverTimeoutObj = setTimeout(function(){//如果超過一定時間還沒重置,說明后端主動斷開了 ws.close(); //如果onclose會執(zhí)行reconnect,我們執(zhí)行ws.close()就行了.如果直接執(zhí)行reconnect 會觸發(fā)onclose導致重連兩次 }, self.timeout) }, this.timeout) }}
js部分使用的是原生H5編寫的,如果為了更好的兼容瀏覽器,也可以使用SockJS,有興趣小伙伴們可以自行百度。
接下來我們就手動的優(yōu)化代碼,實現(xiàn)WebSocket對分布式架構(gòu)的支持。
現(xiàn)在我們已經(jīng)了解單體應用下的代碼結(jié)構(gòu),也清楚了WebSocket在分布式環(huán)境下面臨的問題,那么是時候思考一下如何能夠解決這個問題了。
我們先來看一看發(fā)生這個問題的根本原因是什么。
簡單思考一下就能明白,單體應用下只有一臺服務器,所有的客戶端連接的都是這一臺消息服務器,所以當發(fā)布消息者發(fā)送消息時,所有的客戶端其實已經(jīng)全部與這臺服務器建立了連接,直接群發(fā)消息就可以了。
換成分布式系統(tǒng)后,假如我們有兩臺消息服務器,那么客戶端通過Nginx 增加后刪除掉原來的Websocket推送部分代碼。 到此,相信大家對“分布式下的WebSocket解決方案是什么”有了更深的了解,不妨來實際操作一番吧!這里是創(chuàng)新互聯(lián)網(wǎng)站,更多相關內(nèi)容可以進入相關頻道進行查詢,關注我們,繼續(xù)學習!
當前標題:分布式下的WebSocket解決方案是什么
鏈接URL:http://weahome.cn/article/isgiod.html