WebSocket浅析

一、WebSocket服务端创建

1.创建WebSocket服务端方式(注解)

//通过该注解来创建WebSocket服务端,括号里面是服务端路径
@ServerEndpoint("/websocket/{userID}")
public class WebSocketServer {
     * 连接建立成功调用的方法
     * @param session  可选的参数。session为与某个客户端的连接会话,需要通过它来给客户端发送数据
    @OnOpen
    public void onOpen(@PathParam("userID")Long userID, Session session){
        System.out.println("webSocket客户端建立了连接!");
     * 连接关闭调用的方法
    @OnClose
    public void onClose(){
       System.out.println("webSocket客户端关闭了连接");
     * 收到客户端消息后调用的方法
     * @param message 客户端发送过来的消息
    @OnMessage
    public static void onMessage(String message){
        System.out.println("从客户断接受到的消息:"+message);
     * 发生错误时调用
     * @param session
     * @param error
    @OnError
    public void onError(Session session, Throwable error){
        System.out.println("连接出错,错误类型是:"+error);

注意:创建webSocket的服务端最好用tomcat8以上的服务器,如果用低版本的tomcat服务器,可能又造成冲突

2.创建WebSocket客户端(前端)

    var websocket = null;
    //判断当前浏览器是否支持WebSocket
    if('WebSocket' in window){
       websocket = new WebSocket("ws://localhost:8080/websocket/1")
    else{//ws://localhost:8080/websocket
        alert('Not support websocket');
    //连接发生错误的回调方法
    websocket.onerror = function(){
        setMessageInnerHTML("error");
    //连接成功建立的回调方法
    websocket.onopen = function(event){
        setMessageInnerHTML("open");
    //接收到消息的回调方法
    websocket.onmessage = function(event){
        setMessageInnerHTML(event.data);
        //alert("收到传递的信息!");
    //连接关闭的回调方法
    websocket.onclose = function(){
        setMessageInnerHTML("close");

3、WebSocket服务端线程安全问题

  • WebSocket服务端@onMessage注解的方法,如果有多个线程同时连接了服务端,向服务端传输数据,可能会造成线程的安全问题,报错
  • * 收到客户端消息后调用的方法 * @param message 客户端发送过来的消息 @OnMessage public static void onMessage(String message){ session.getBasicRemote().sendText("用户ID:"+id+"已经接受到消息,并且向客户端返回消息,返回的消息:"+message); System.out.println("从客户断接受到的消息:"+message);
  • 上图中的方法是线程不安全的,笔者通过Jmeter测试工具来进行多线程压力测试,果然出现了数据写入出错的问题
  •  @OnMessage
        public synchronized static void onMessage(String message){
        session.getBasicRemote().sendText("用户ID:"+id+"已经接受到消息,并且向客户端返回消息,返回的消息:"+message);
            System.out.println("从客户断接受到的消息:"+message);
    

    4.webSocket断线重连机制

    var lockReconnect = false;//避免重复连接 var wsUrl = "ws://localhost:8081/websocket/1"; var ws =null; var time; function createWebSocket() { try { ws = new WebSocket(wsUrl); init(); } catch (e) { console.log("e"); reconnect(wsUrl) function init() { //连接发生错误的回调方法 ws.onerror = function () { setMessageInnerHTML("error"); reconnect(wsUrl); //连接成功建立的回调方法 ws.onopen = function (event) { setMessageInnerHTML("open"); heartCheck.start(); //接收到消息的回调方法 ws.onmessage = function (event) { setMessageInnerHTML(event.data); //alert("收到传递的信息!"); heartCheck.start(); //连接关闭的回调方法 ws.onclose = function () { setMessageInnerHTML("close"); reconnect(wsUrl); //监听窗口关闭事件,当窗口关闭时,主动去关闭websocket连接,防止连接还没断开就关闭窗口,server端会抛异常。 window.onbeforeunload = function () { ws.close(); function reconnect(url) { if (lockReconnect) { return; lockReconnect == true; //没连接上会一直重连,设置延迟避免请求过多 time && clearTimeout(time) time = setTimeout(function () { createWebSocket(url); lockReconnect = false; }, 4000) //心跳检测 var heartCheck = { timeOut: 3000, timeOutObj: null, serverTimeOutObj: null, start: function () { var self = this; //将关闭客户端的延迟方法取消 self.serverTimeOutObj && clearTimeout(self.serverTimeOutObj); self.timeOutObj = setTimeout(function () { //这里发送一个心跳消息,后端收到心跳消息后返回一个心跳消息,采用延迟2秒发送避免造成服务端消息堵塞 ws.send("12345678"); //创建延迟方法,如果2秒钟后台没有响应消息,客户端就会关闭连接,触发websocket重连 self.serverTimeOutObj = setTimeout(function() { ws.close(); // createWebSocket(); }, 2000); },2000) function setMessageInnerHTML(innerHTML) { document.getElementById('message').innerHTML += innerHTML + '<br/>'; //页面初始化时创建连接 createWebSocket(wsUrl);

    断线重连效果