版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qy_0626/article/details/86086197
本文旨在记录如何实现小程序使用websocket接受/推送消息
- websocket 是什么
- websocket 服务器端和客户端
- 小程序如何和websocket建立连接,并实现消息推送/接受
websocket是什么?
websocket是一种通信协议,它使得我们可以建立双方连接的通道,也就是说的握手。通信不仅可以从客户端发起,也可以从服务器主动给客户端发送消息,典型使用场景就是类似多人聊天,一个客户端说话,其他的客户端也可以收到消息
详细可参考以下博客:
WebSocket 服务器端和客户端
服务器端:相当于一个中间站,每个客户端和它建立连接,当一个客户端给它发送消息时,服务器端收到消息,然后发送消息给其他建立连接的客户端,以下为服务器端实现推送简单的demo:
package com.net.websocket;
import java.io.IOException;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.Collection;
import javax.websocket.*;
import javax.websocket.server.ServerEndpoint;
/**
* @ServerEndpoint 注解是一个类层次的注解,它的功能主要是将目前的类定义成一个websocket服务器端,
* 注解的值将被用于监听用户连接的终端访问URL地址,客户端可以通过这个URL来连接到WebSocket服务器端
*/
@ServerEndpoint("/websocket")
public class WebSocket {
//静态变量,用来记录当前在线连接数。应该把它设计成线程安全的。
private static int onlineCount = 0;
//concurrent包的线程安全Set,用来存放每个客户端对应的MyWebSocket对象。若要实现服务端与单一客户端通信的话,可以使用Map来存放,其中Key可以为用户标识
// private static CopyOnWriteArraySet<WebSocket> webSocketSet = new CopyOnWriteArraySet<WebSocket>();
private static ConcurrentMap<String, WebSocket> webSocketMap = new ConcurrentHashMap<String, WebSocket>();
//与某个客户端的连接会话,需要通过它来给客户端发送数据
private Session session;
/**
* 连接建立成功调用的方法
* @param session 可选的参数。session为与某个客户端的连接会话,需要通过它来给客户端发送数据
*/
@OnOpen
public void onOpen(Session session) {
try {
this.session = session;
System.out.println("==> session.getQueryString:" + session.getQueryString());
String str = session.getQueryString();
String[] list = str.split("_");
String sessionId = "";
if(list.length>0){
sessionId = list[0]; //第一个参数作为当前建立连接的sessionkey
webSocketMap.put(sessionId,this); //将这个会话加入到Map中
addOnlineCount(); //在线数加1
System.out.println("count:" + getOnlineCount());
}
// webSocketSet.add(this); //加入set中
}catch (Exception e){
e.printStackTrace();
System.out.println("open error:" + e.getMessage());
}
}
/**
* 连接关闭调用的方法
*/
@OnClose
public void onClose(){
// webSocketSet.remove(this); //从set中删除
String str = session.getQueryString();
String[] list = str.split("_");
String sessionId = "";
if(list.length>0){
sessionId = list[0];
System.out.println("Client ID:"+list[0]);
webSocketMap.remove(sessionId);//从map中删除
subOnlineCount(); //在线数减1
System.out.println("current num :" + getOnlineCount());
}
}
/**
* 收到客户端消息后调用的方法
* @param message 客户端发送过来的消息
* @param session 可选的参数
* @throws IOException e
*/
@OnMessage
public void onMessage(String message, Session session){
try {
System.out.println("message :" + message);
System.out.println("session :" + session.getQueryString());
String str = session.getQueryString();
String[] list = str.split("_");
String sessionId = "";
if(list.length>0){
sessionId = list[0]; //第一个参数作为当前建立连接的sessionkey
System.out.println("Messages from Client:"+list[0]);
for(String sessionkey : list){
if(sessionkey != list[0]){
System.out.println("send message to :" + sessionkey);
WebSocket webSocket= webSocketMap.get(sessionkey);
if(webSocket != null){
System.out.println("Sending a message, please wait a moment...");
webSocket.sendMessage(message);
}
}
}
}
} catch (Exception e) {
System.out.println("receive messages error:"+e.getMessage());
e.printStackTrace();
}
}
/**
* 发送消息方法。
* @param message 消息内容
* @throws IOException Exception
*/
private void sendMessage(String message) {
try{
this.session.getBasicRemote().sendText(message);
System.out.println("send successful !");
}catch (Exception e){
e.printStackTrace();
System.out.println("send error:"+e.getMessage());
}
//this.session.getAsyncRemote().sendText(message);
}
/**
* 群发消息 给所有奖励链接的客户端发送一条消息
* @param message 消息内容
*/
private void sendMessageAll(String message){
try {
Collection<WebSocket> values = webSocketMap.values();
for(WebSocket webSocket : values ){
try {
webSocket.sendMessage(message);
}catch (Exception e){
System.out.println("send message to client error:"+e.getMessage());
e.printStackTrace();
}
}
}catch (Exception e){
System.out.println("send message all error:"+e.getMessage());
e.printStackTrace();
}
}
/**
* 发生错误时调用
* @param session
* @param error
*/
@OnError
public void onError(Session session, Throwable error){
System.out.println("error:"+error);
// error.printStackTrace();
}
public static synchronized int getOnlineCount() {
return onlineCount;
}
public static synchronized void addOnlineCount() {
WebSocket.onlineCount++;
}
public static synchronized void subOnlineCount() {
WebSocket.onlineCount--;
}
}
客户端:实现客户端的方式有多种,例如html5 springboot 小程序等 以下为springboot为例:
package com.net.client;
import javax.websocket.*;
import java.io.IOException;
import java.net.URI;
/**
* 客户端
* Created by zhangq on 2018/12/21.
*/
@javax.websocket.ClientEndpoint
public class ClientEndpoint {
private Session session;
/**
* 与服务端建立连接
* @param session 会话
*/
@OnOpen
public void onOpen(Session session) {
System.out.println("Connected to endpoint: " + session.getBasicRemote());
try {
this.session=session;
System.out.println(this.session);
} catch (Exception ex) {
ex.printStackTrace();
}
}
/**
* 接受来自服务端的消息 即客户端收到的消息
* @param message 消息内容
*/
@OnMessage
public void processMessage(String message) {
System.out.println("Received message in client: " + message);
}
/**
* 发生错误时调用
* @param t
*/
@OnError
public void processError(Throwable t) {
t.printStackTrace();
}
/**
* 连接关闭调用的方法
* @throws Exception
*/
@OnClose
public void onClose() throws Exception{
}
/**
* 关闭链接方法
* @throws IOException e
*/
public void closeSocket() throws IOException {
this.session.close();
}
/**
* 发送消息方法。
* @param message 消息内容
* @throws IOException e
*/
public void sendMessage(String message) throws IOException{
this.session.getBasicRemote().sendText(message);
}
/**
* 启动客户端并建立链接
* @param uri 服务端地址
*/
public void start(String uri) {
WebSocketContainer container = ContainerProvider.getWebSocketContainer();
try {
this.session = container.connectToServer(ClientEndpoint.class, URI.create(uri));
} catch (Exception e) {
e.printStackTrace();
}
}
}
package com.net.crud.utils;
import com.net.client.ClientEndpoint;
import java.util.Map;
/**
* 发送消息Util
* Created by zhangq on 2018/12/22.
*/
public class MessageUtil {
private static final String ws = "ws://localhost:8080/websocket?000"; //固定此客户端地址 用来向其他客户端发送消息
/**
* 发送消息给指定的客户端
* @param sessionkey 客户端的sessionkey
* @param message 消息内容
* @return success/error
*/
public static Object sendMsg(String sessionkey,String message){
try {
StringBuffer uri = new StringBuffer(ws).append("_").append(sessionkey);
ClientEndpoint client = new ClientEndpoint();
client.start(new String(uri));
try {
client.sendMessage(message);
client.closeSocket();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return "success";
} catch ( Exception ex) {
ex.printStackTrace();
return "error";
}
}
}
小程序如何和websocket建立连接,并实现消息推送/接受
使用小程序官方提供的 WebSocket SocketTask实现 以下为示例代码:
app.js 定义全局唯一的localSocket
//app.js
var req = require('libs/client.js');
App({
onLaunch: function () {
},
globalData: {
ws: "ws://localhost/websocket",
localSocket: {},
callback: function () { }
},
initSocket() { //初始化websocket 添加监听
let that = this
that.globalData.localSocket = wx.connectSocket({
url: that.globalData.ws
})
//监听 WebSocket 连接打开事件
that.globalData.localSocket.onOpen(function (res) {
console.log('WebSocket连接已打开!readyState=' + that.globalData.localSocket.readyState)
})
//监听 WebSocket 接受到服务器的消息事件
that.globalData.localSocket.onMessage(function (res) {
that.globalData.callback(res)
})
//监听 WebSocket 错误事件
that.globalData.localSocket.onError(function (res) {
console.log('WebSocket错误!readyState=' + that.globalData.localSocket.readyState)
})
//监听 WebSocket 连接关闭事件
that.globalData.localSocket.onClose(function (res) {
console.log('WebSocket连接已关闭!readyState=' + that.globalData.localSocket.readyState)
that.initSocket()
})
},
sendSocketMessage: function (msg) {//统一发送消息
if (this.globalData.localSocket.readyState === 1) {
this.globalData.localSocket.send({
data: msg,
success(res){
// console.log("成功发送消息:" + msg);
}
})
}
},
onShow: function (options) {
if (this.globalData.localSocket.readyState !== 0 && this.globalData.localSocket.readyState !== 1) {
console.log('开始尝试连接WebSocket!readyState=' + this.globalData.localSocket.readyState)
this.initSocket();
}
}
})
另外一个页面 接受消息回调
//index.js
var app = getApp()
Page({
data: {
},
onShow: function () {
var that = this
//创建websocket客户端 并建立连接
if (app.globalData.localSocket.readyState !== 0 && app.globalData.localSocket.readyState !== 1) {
console.log('开始尝试连接WebSocket!readyState=' + app.globalData.localSocket.readyState)
app.initSocket();
}
//监听消息
app.globalData.callback = function (res) {
console.log("接受消息推送:");
console.log(res.data);
}
}
})