微信小程序使用websocket通訊的demo,含前后端代碼,親測(cè)可用
0、概述websocket
(1) 個(gè)人總結(jié):后臺(tái)設(shè)置了websocket地址,服務(wù)器開啟后等待有人去連接它。 一個(gè)客戶端一打開就去連接websocket地址,同時(shí)傳遞某些識(shí)別參數(shù)。這樣一來后臺(tái)和客戶端連接成功了,然后后臺(tái)就可以發(fā)消息給客戶端了,(客戶端也可以再回話給后臺(tái))。
(2) socket叫套接字,應(yīng)用程序用socket向網(wǎng)絡(luò)發(fā)出請(qǐng)求或者應(yīng)答網(wǎng)絡(luò)請(qǐng)求。
(3) 官方解釋的socket 建立連接四步驟:
服務(wù)器端開啟socket,然后accep方法處于監(jiān)聽狀態(tài),等待客戶端的連接。
客戶端開啟,指定服務(wù)器名稱和端口號(hào)來請(qǐng)求連接服務(wù)器端的socket。
服務(wù)器端收到客戶端連接請(qǐng)求,返回連接確認(rèn)。在服務(wù)器端,accept() 方法返回服務(wù)器上一個(gè)新的 socket 引用,該 socket 連接到客戶端的 socket。
客戶端收到連接確認(rèn),兩個(gè)人就連接好了,雙方開始通訊
(4)注意:
客戶端的輸出流連接到服務(wù)器端的輸入流,而客戶端的輸入流連接到服務(wù)器端的輸出流。
TCP 是一個(gè)雙向的通信協(xié)議,因此數(shù)據(jù)可以通過兩個(gè)數(shù)據(jù)流在同一時(shí)間發(fā)送.
1、app.js寫法
在app.js下添加三個(gè)函數(shù)openSocket(), closeSocket(),sendMessage(),在app初始化的onLunch函數(shù)里面調(diào)用openSocket(),這樣子用戶一進(jìn)入小程序就會(huì)自動(dòng)連接websocket
App({ globalData: { socketStatus: 'closed', }, onLaunch: function() { var that = this; if (that.globalData.socketStatus === 'closed') { that.openSocket(); } } openSocket() { //打開時(shí)的動(dòng)作 wx.onSocketOpen(() => { console.log('WebSocket 已連接') this.globalData.socketStatus = 'connected'; this.sendMessage(); }) //斷開時(shí)的動(dòng)作 wx.onSocketClose(() => { console.log('WebSocket 已斷開') this.globalData.socketStatus = 'closed' }) //報(bào)錯(cuò)時(shí)的動(dòng)作 wx.onSocketError(error => { console.error('socket error:', error) }) // 監(jiān)聽服務(wù)器推送的消息 wx.onSocketMessage(message => { //把JSONStr轉(zhuǎn)為JSON message = message.data.replace(" ", ""); if (typeof message != 'object') { message = message.replace(/\ufeff/g, ""); //重點(diǎn) var jj = JSON.parse(message); message = jj; } console.log("【websocket監(jiān)聽到消息】?jī)?nèi)容如下:"); console.log(message); }) // 打開信道 wx.connectSocket({ url: "ws://" + "localhost" + ":8888", }) }, //關(guān)閉信道 closeSocket() { if (this.globalData.socketStatus === 'connected') { wx.closeSocket({ success: () => { this.globalData.socketStatus = 'closed' } }) } }, //發(fā)送消息函數(shù) sendMessage() { if (this.globalData.socketStatus === 'connected') { //自定義的發(fā)給后臺(tái)識(shí)別的參數(shù) ,我這里發(fā)送的是name wx.sendSocketMessage({ data: "{\"name\":\"" + wx.getStorageSync('openid') + "\"}" }) } }, })
2、后臺(tái)寫法
主要有兩個(gè)類,一個(gè)是websocket啟動(dòng)監(jiān)聽交互類,一個(gè)是存儲(chǔ)當(dāng)前所有已經(jīng)連接好的用戶池以及對(duì)這些用戶的操作封裝類
然后在項(xiàng)目啟動(dòng)類里面調(diào)用websocke啟動(dòng)監(jiān)聽交互類的啟動(dòng)方法。(如果是springboot項(xiàng)目,就直接在主類中調(diào)用)
(1)導(dǎo)入包
<dependency> <groupId>org.java-websocket</groupId> <artifactId>Java-WebSocket</artifactId> <version>1.3.0</version> </dependency>
(2)啟動(dòng)websocket的方法,放在啟動(dòng)類里面
/** * 啟動(dòng)websocket */ public void startWebsocketInstantMsg() { WebSocketImpl.DEBUG = false; MyWebScoket s; s = new MyWebScoket(8888); s.start(); System.out.println("websocket啟動(dòng)成功"); }
(3)websocket監(jiān)聽交互類如下
該類涉及的監(jiān)聽方法有:監(jiān)聽用戶連入;監(jiān)聽用戶斷開;監(jiān)聽消息發(fā)過來;監(jiān)聽有錯(cuò)誤等
import com.alibaba.fastjson.JSONObject; import org.java_websocket.WebSocket; import org.java_websocket.handshake.ClientHandshake; import org.java_websocket.server.WebSocketServer; import java.net.InetSocketAddress; import java.net.UnknownHostException; import java.util.Map; public class MyWebScoket extends WebSocketServer { public MyWebScoket() throws UnknownHostException { super(); } public MyWebScoket(int port) { super(new InetSocketAddress(port)); } public MyWebScoket(InetSocketAddress address) { super(address); } @Override public void onOpen(WebSocket conn, ClientHandshake handshake) { // ws連接的時(shí)候觸發(fā)的代碼,onOpen中我們不做任何操作 } @Override public void onClose(WebSocket conn, int code, String reason, boolean remote) { //斷開連接時(shí)候觸發(fā)代碼 userLeave(conn); System.out.println(reason); } @Override public void onMessage(WebSocket conn, String message) { //有用戶連接進(jìn)來 Map<String, String> obj = (Map<String,String>) JSONObject.parse(message); System.out.println(message); String username = obj.get("name"); userJoin(conn, username); } @Override public void onError(WebSocket conn, Exception ex) { //錯(cuò)誤時(shí)候觸發(fā)的代碼 System.out.println("on error"); ex.printStackTrace(); } /** * 去除掉失效的websocket鏈接 */ private void userLeave(WebSocket conn){ WsPool.removeUser(conn); } /** * 將websocket加入用戶池 * @param conn * @param userName */ private void userJoin(WebSocket conn,String userName){ WsPool.addUser(userName, conn); } }
(4)用戶池類如下
該類包含的方法有:從池中移除或添加用戶;獲取當(dāng)前在線的所有用戶;通過參數(shù)"name"獲取某個(gè)用戶的當(dāng)前WebSocket連接;給某個(gè)WebSocket連接發(fā)送消息;為所有WebSocket連接發(fā)送消息等等
import com.td.yousan.util.StringUtils; import org.java_websocket.WebSocket; import java.util.*; public class WsPool { private static final Map<WebSocket, String> wsUserMap = new HashMap<WebSocket, String>(); /** * 通過websocket連接獲取其對(duì)應(yīng)的用戶 */ public static String getUserByWs(WebSocket conn) { return wsUserMap.get(conn); } /** * 根據(jù)userName獲取WebSocket,這是一個(gè)list,此處取第一個(gè) * 因?yàn)橛锌赡芏鄠€(gè)websocket對(duì)應(yīng)一個(gè)userName(但一般是只有一個(gè),因?yàn)樵赾lose方法中,我們將失效的websocket連接去除了) */ public static WebSocket getWsByUser(String userName) { Set<WebSocket> keySet = wsUserMap.keySet(); synchronized (keySet) { for (WebSocket conn : keySet) { String cuser = wsUserMap.get(conn); if (cuser.equals(userName)) { return conn; } } } return null; } /** * 向連接池中添加連接 */ public static void addUser(String userName, WebSocket conn) { wsUserMap.put(conn, userName); // 添加連接 } /** * 獲取所有連接池中的用戶,因?yàn)閟et是不允許重復(fù)的,所以可以得到無重復(fù)的user數(shù)組 */ public static Collection<String> getOnlineUser() { List<String> setUsers = new ArrayList<String>(); Collection<String> setUser = wsUserMap.values(); for (String u : setUser) { setUsers.add(u); } return setUsers; } /** * 移除連接池中的連接 */ public static boolean removeUser(WebSocket conn) { if (wsUserMap.containsKey(conn)) { wsUserMap.remove(conn); // 移除連接 return true; } else { return false; } } /** * 向特定的用戶發(fā)送數(shù)據(jù) */ public static void sendMessageToUser(WebSocket conn, String message) { if (null != conn && null != wsUserMap.get(conn)) { conn.send(message); } } /** * 向所有用戶名中包含某個(gè)特征得用戶發(fā)送消息 */ public static void sendMessageToSpecialUser(String message,String special) { Set<WebSocket> keySet = wsUserMap.keySet(); if (special == null) { special = ""; } synchronized (keySet) { for (WebSocket conn:keySet) { String user = wsUserMap.get(conn); try { if (user != null) { String [] cus = user.split("_"); if (!StringUtils.isNullOrEmpty(cus[0])) { String cusDot = "," + cus[0] + ","; if (cusDot.contains(","+special+",")) { conn.send(message); } }else { conn.send(message); } } }catch (Exception e) { e.printStackTrace(); //wsUserMap.remove(conn); } } } } /** * 向所有的用戶發(fā)送消息 */ public static void sendMessageToAll(String message) { Set<WebSocket> keySet = wsUserMap.keySet(); synchronized (keySet) { for (WebSocket conn : keySet) { String user = wsUserMap.get(conn); if (user != null) { conn.send(message); } } } } }
總結(jié)
以上所述是小編給大家介紹的微信小程序使用websocket通訊的demo,含前后端代碼,親測(cè)可用,希望對(duì)大家有所幫助,如果大家有任何疑問歡迎給我留言,小編會(huì)及時(shí)回復(fù)大家的!
相關(guān)文章
淺談javascript中的數(shù)據(jù)類型轉(zhuǎn)換
本文主要對(duì)javascript中的數(shù)據(jù)類型轉(zhuǎn)換進(jìn)行介紹,具有一定的參考價(jià)值,下面跟著小編一起來看下吧2016-12-12JavaScript學(xué)習(xí)筆記之?dāng)?shù)組求和方法
這篇文章主要介紹了JavaScript學(xué)習(xí)筆記之?dāng)?shù)組求和方法的相關(guān)資料,需要的朋友可以參考下2016-03-03JavaScript二維數(shù)組實(shí)現(xiàn)的省市聯(lián)動(dòng)菜單
這篇文章主要介紹了使用二維數(shù)組實(shí)現(xiàn)的省市聯(lián)動(dòng)菜單,通過二維數(shù)組存儲(chǔ)城市列表項(xiàng),需要的朋友可以參考下2014-05-05JS彈性運(yùn)動(dòng)實(shí)現(xiàn)方法分析
這篇文章主要介紹了JS彈性運(yùn)動(dòng)實(shí)現(xiàn)方法,結(jié)合實(shí)例形式分析了JS實(shí)現(xiàn)彈性運(yùn)動(dòng)的原理、相關(guān)技術(shù)細(xì)節(jié)與實(shí)現(xiàn)技巧,需要的朋友可以參考下2016-12-12微信小程序?qū)崿F(xiàn)tab點(diǎn)擊切換
這篇文章主要為大家詳細(xì)介紹了微信小程序?qū)崿F(xiàn)tab點(diǎn)擊切換,不滑動(dòng),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-07-07JavaScript將頁面表格導(dǎo)出為Excel的具體實(shí)現(xiàn)
如何將頁面表格導(dǎo)出為Excel,這在日常工作中很常見,下面為大家詳細(xì)的介紹下使用JavaScript是如何實(shí)現(xiàn)的2013-12-12JS實(shí)現(xiàn)商品倒計(jì)時(shí)實(shí)現(xiàn)代碼
JS實(shí)現(xiàn)商品倒計(jì)時(shí)實(shí)現(xiàn)代碼,需要的朋友可以參考一下2013-05-05javascript數(shù)據(jù)類型中的一些小知識(shí)點(diǎn)(推薦)
這篇文章主要介紹了javascript數(shù)據(jù)類型中的一些小知識(shí)點(diǎn),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-04-04javascript實(shí)現(xiàn)數(shù)組中的內(nèi)容隨機(jī)輸出
本文實(shí)例講述了javaScript數(shù)組隨機(jī)排列實(shí)現(xiàn)隨機(jī)洗牌功能的方法。分享給大家供大家參考。2015-08-08js實(shí)現(xiàn)div色塊拖動(dòng)錄制
這篇文章主要為大家詳細(xì)介紹了js實(shí)現(xiàn)div色塊拖動(dòng)錄制,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2020-01-01