微信小程序使用websocket通訊的demo,含前后端代碼,親測可用
0、概述websocket
(1) 個人總結(jié):后臺設(shè)置了websocket地址,服務(wù)器開啟后等待有人去連接它。 一個客戶端一打開就去連接websocket地址,同時傳遞某些識別參數(shù)。這樣一來后臺和客戶端連接成功了,然后后臺就可以發(fā)消息給客戶端了,(客戶端也可以再回話給后臺)。
(2) socket叫套接字,應(yīng)用程序用socket向網(wǎng)絡(luò)發(fā)出請求或者應(yīng)答網(wǎng)絡(luò)請求。
(3) 官方解釋的socket 建立連接四步驟:
服務(wù)器端開啟socket,然后accep方法處于監(jiān)聽狀態(tài),等待客戶端的連接。
客戶端開啟,指定服務(wù)器名稱和端口號來請求連接服務(wù)器端的socket。
服務(wù)器端收到客戶端連接請求,返回連接確認(rèn)。在服務(wù)器端,accept() 方法返回服務(wù)器上一個新的 socket 引用,該 socket 連接到客戶端的 socket。
客戶端收到連接確認(rèn),兩個人就連接好了,雙方開始通訊
(4)注意:
客戶端的輸出流連接到服務(wù)器端的輸入流,而客戶端的輸入流連接到服務(wù)器端的輸出流。
TCP 是一個雙向的通信協(xié)議,因此數(shù)據(jù)可以通過兩個數(shù)據(jù)流在同一時間發(fā)送.
1、app.js寫法
在app.js下添加三個函數(shù)openSocket(), closeSocket(),sendMessage(),在app初始化的onLunch函數(shù)里面調(diào)用openSocket(),這樣子用戶一進(jìn)入小程序就會自動連接websocket
App({
globalData: {
socketStatus: 'closed',
},
onLaunch: function() {
var that = this;
if (that.globalData.socketStatus === 'closed') {
that.openSocket();
}
}
openSocket() {
//打開時的動作
wx.onSocketOpen(() => {
console.log('WebSocket 已連接')
this.globalData.socketStatus = 'connected';
this.sendMessage();
})
//斷開時的動作
wx.onSocketClose(() => {
console.log('WebSocket 已斷開')
this.globalData.socketStatus = 'closed'
})
//報錯時的動作
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)聽到消息】內(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ā)給后臺識別的參數(shù) ,我這里發(fā)送的是name
wx.sendSocketMessage({
data: "{\"name\":\"" + wx.getStorageSync('openid') + "\"}"
})
}
},
})
2、后臺寫法
主要有兩個類,一個是websocket啟動監(jiān)聽交互類,一個是存儲當(dāng)前所有已經(jīng)連接好的用戶池以及對這些用戶的操作封裝類
然后在項目啟動類里面調(diào)用websocke啟動監(jiān)聽交互類的啟動方法。(如果是springboot項目,就直接在主類中調(diào)用)
(1)導(dǎo)入包
<dependency> <groupId>org.java-websocket</groupId> <artifactId>Java-WebSocket</artifactId> <version>1.3.0</version> </dependency>
(2)啟動websocket的方法,放在啟動類里面
/**
* 啟動websocket
*/
public void startWebsocketInstantMsg() {
WebSocketImpl.DEBUG = false;
MyWebScoket s;
s = new MyWebScoket(8888);
s.start();
System.out.println("websocket啟動成功");
}
(3)websocket監(jiān)聽交互類如下
該類涉及的監(jiān)聽方法有:監(jiān)聽用戶連入;監(jiān)聽用戶斷開;監(jiān)聽消息發(fā)過來;監(jiān)聽有錯誤等
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連接的時候觸發(fā)的代碼,onOpen中我們不做任何操作
}
@Override
public void onClose(WebSocket conn, int code, String reason, boolean remote) {
//斷開連接時候觸發(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) {
//錯誤時候觸發(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"獲取某個用戶的當(dāng)前WebSocket連接;給某個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連接獲取其對應(yīng)的用戶
*/
public static String getUserByWs(WebSocket conn) {
return wsUserMap.get(conn);
}
/**
* 根據(jù)userName獲取WebSocket,這是一個list,此處取第一個
* 因?yàn)橛锌赡芏鄠€websocket對應(yīng)一個userName(但一般是只有一個,因?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);
}
}
/**
* 向所有用戶名中包含某個特征得用戶發(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,含前后端代碼,親測可用,希望對大家有所幫助,如果大家有任何疑問歡迎給我留言,小編會及時回復(fù)大家的!
相關(guān)文章
淺談javascript中的數(shù)據(jù)類型轉(zhuǎn)換
本文主要對javascript中的數(shù)據(jù)類型轉(zhuǎn)換進(jìn)行介紹,具有一定的參考價值,下面跟著小編一起來看下吧2016-12-12
JavaScript學(xué)習(xí)筆記之?dāng)?shù)組求和方法
這篇文章主要介紹了JavaScript學(xué)習(xí)筆記之?dāng)?shù)組求和方法的相關(guān)資料,需要的朋友可以參考下2016-03-03
JavaScript二維數(shù)組實(shí)現(xiàn)的省市聯(lián)動菜單
這篇文章主要介紹了使用二維數(shù)組實(shí)現(xiàn)的省市聯(lián)動菜單,通過二維數(shù)組存儲城市列表項,需要的朋友可以參考下2014-05-05
微信小程序?qū)崿F(xiàn)tab點(diǎn)擊切換
這篇文章主要為大家詳細(xì)介紹了微信小程序?qū)崿F(xiàn)tab點(diǎn)擊切換,不滑動,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下2022-07-07
JavaScript將頁面表格導(dǎo)出為Excel的具體實(shí)現(xiàn)
如何將頁面表格導(dǎo)出為Excel,這在日常工作中很常見,下面為大家詳細(xì)的介紹下使用JavaScript是如何實(shí)現(xiàn)的2013-12-12
JS實(shí)現(xiàn)商品倒計時實(shí)現(xiàn)代碼
JS實(shí)現(xiàn)商品倒計時實(shí)現(xiàn)代碼,需要的朋友可以參考一下2013-05-05
javascript數(shù)據(jù)類型中的一些小知識點(diǎn)(推薦)
這篇文章主要介紹了javascript數(shù)據(jù)類型中的一些小知識點(diǎn),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-04-04
javascript實(shí)現(xiàn)數(shù)組中的內(nèi)容隨機(jī)輸出
本文實(shí)例講述了javaScript數(shù)組隨機(jī)排列實(shí)現(xiàn)隨機(jī)洗牌功能的方法。分享給大家供大家參考。2015-08-08

