小程序开发之WebSocket

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qy_0626/article/details/86086197

本文旨在记录如何实现小程序使用websocket接受/推送消息

  • websocket 是什么
  • 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);
    }
  }
})

猜你喜欢

转载自blog.csdn.net/qy_0626/article/details/86086197
今日推荐