[TOC] 0、概述websocket (1) 個人總結:後臺設置了websocket地址,伺服器開啟後等待有人去連接它。 一個客戶端一打開就去連接websocket地址,同時傳遞某些識別參數。這樣一來後臺和客戶端連接成功了,然後後臺就可以發消息給客戶端了,(客戶端也可以再回話給後臺)。 (2) s ...
目錄
0、概述websocket
(1) 個人總結:後臺設置了websocket地址,伺服器開啟後等待有人去連接它。 一個客戶端一打開就去連接websocket地址,同時傳遞某些識別參數。這樣一來後臺和客戶端連接成功了,然後後臺就可以發消息給客戶端了,(客戶端也可以再回話給後臺)。
(2) socket叫套接字,應用程式用socket向網路發出請求或者應答網路請求。
(3) 官方解釋的socket 建立連接四步驟:
伺服器端開啟socket,然後accep方法處於監聽狀態,等待客戶端的連接。
客戶端開啟,指定伺服器名稱和埠號來請求連接伺服器端的socket。
伺服器端收到客戶端連接請求,返回連接確認。在伺服器端,accept() 方法返回伺服器上一個新的 socket 引用,該 socket 連接到客戶端的 socket。
客戶端收到連接確認,兩個人就連接好了,雙方開始通訊
(4)註意:
客戶端的輸出流連接到伺服器端的輸入流,而客戶端的輸入流連接到伺服器端的輸出流。
TCP 是一個雙向的通信協議,因此數據可以通過兩個數據流在同一時間發送.
1、app.js寫法
在app.js下添加三個函數openSocket(), closeSocket(),sendMessage(),在app初始化的onLunch函數裡面調用openSocket(),這樣子用戶一進入小程式就會自動連接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)
})
// 監聽伺服器推送的消息
wx.onSocketMessage(message => {
//把JSONStr轉為JSON
message = message.data.replace(" ", "");
if (typeof message != 'object') {
message = message.replace(/\ufeff/g, ""); //重點
var jj = JSON.parse(message);
message = jj;
}
console.log("【websocket監聽到消息】內容如下:");
console.log(message);
})
// 打開通道
wx.connectSocket({
url: "ws://" + "localhost" + ":8888",
})
},
//關閉通道
closeSocket() {
if (this.globalData.socketStatus === 'connected') {
wx.closeSocket({
success: () => {
this.globalData.socketStatus = 'closed'
}
})
}
},
//發送消息函數
sendMessage() {
if (this.globalData.socketStatus === 'connected') {
//自定義的發給後臺識別的參數 ,我這裡發送的是name
wx.sendSocketMessage({
data: "{\"name\":\"" + wx.getStorageSync('openid') + "\"}"
})
}
},
})
2、後臺寫法
主要有兩個類,一個是websocket啟動監聽交互類,一個是存儲當前所有已經連接好的用戶池以及對這些用戶的操作封裝類。
然後在項目啟動類裡面調用websocke啟動監聽交互類的啟動方法。(如果是springboot項目,就直接在主類中調用)
(1)導入包
<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監聽交互類如下
該類涉及的監聽方法有:監聽用戶連入;監聽用戶斷開;監聽消息發過來;監聽有錯誤等
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連接的時候觸發的代碼,onOpen中我們不做任何操作
}
@Override
public void onClose(WebSocket conn, int code, String reason, boolean remote) {
//斷開連接時候觸發代碼
userLeave(conn);
System.out.println(reason);
}
@Override
public void onMessage(WebSocket conn, String message) {
//有用戶連接進來
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) {
//錯誤時候觸發的代碼
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)用戶池類如下
該類包含的方法有:從池中移除或添加用戶;獲取當前線上的所有用戶;通過參數"name"獲取某個用戶的當前WebSocket連接;給某個WebSocket連接發送消息;為所有WebSocket連接發送消息等等
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連接獲取其對應的用戶
*/
public static String getUserByWs(WebSocket conn) {
return wsUserMap.get(conn);
}
/**
* 根據userName獲取WebSocket,這是一個list,此處取第一個
* 因為有可能多個websocket對應一個userName(但一般是只有一個,因為在close方法中,我們將失效的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); // 添加連接
}
/**
* 獲取所有連接池中的用戶,因為set是不允許重覆的,所以可以得到無重覆的user數組
*/
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;
}
}
/**
* 向特定的用戶發送數據
*/
public static void sendMessageToUser(WebSocket conn, String message) {
if (null != conn && null != wsUserMap.get(conn)) {
conn.send(message);
}
}
/**
* 向所有用戶名中包含某個特征得用戶發送消息
*/
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);
}
}
}
}
/**
* 向所有的用戶發送消息
*/
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);
}
}
}
}
}