WebSocket原理介紹和應用

一、相關概念原理

懶得寫了,這裏有介紹:https://my.oschina.net/kdy1994/blog/809802java

二、WebSocket生命週期

  • 打開:@OnOpen;void方法,可選帶參數一個Session、一個EndPointConfig、任意多個@PathParam
  • 消息:@OnMessage;方法參數一個Session、一個EndPointConfig、任意多個@PathParam、消息、分片標誌位(Boolean,true-最後;false-非)
                消息類型
                        *文本消息:String、Reader
                        *二進制:ByteBuffer、byte[]、InputStream
                        pong消息:PongMessage接口實例
                返回類型
                        void:
                        非 void:會將返回值發送給消息的發送者。
  • 錯誤:@OnError:可帶錯誤消息Throwable、Session、多個@PathParam
  • 關閉:@OnClose:可帶關閉信息CloseReason、Session、多個@PathParam

三、WebSocket的應用與實現

最新的一個項目中由於要控制用戶只能在一個地方登錄,及時顯示登陸狀況信息,就是用的WebSocket實現的web

服務端實現json

   @EnableWebSocket  聲明該類支持WebSocket瀏覽器

/**
 * @ServerEndpoint 註解是一個類層次的註解,它的功能主要是將目前的類定義成一個websocket服務器端,
 * 註解的值將被用於監聽用戶鏈接的終端訪問URL地址,客戶端能夠經過這個URL來鏈接到WebSocket服務器端
 */
@ServerEndpoint("/websocket/{tstr}")
public class WebSocketForJSP {
    //concurrent包的線程安全Set,用來存放每一個客戶端對應的MyWebSocket對象。若要實現服務端與單一客戶端通訊的話,可使用Map來存放,其中Key能夠爲用戶標識
    public static CopyOnWriteArraySet<WebSocketForJSP> webSocketSet = new CopyOnWriteArraySet<WebSocketForJSP>();

    //與某個客戶端的鏈接會話,須要經過它來給客戶端發送數據
    private Session session;
    // 登陸用戶名
    public String userName;
    //所屬IP
    public String ip;
    
    
   
    /**
     * 鏈接創建成功調用的方法
     * @param session  可選的參數。session爲與某個客戶端的鏈接會話,須要經過它來給客戶端發送數據
     */
    @OnOpen
    public void onOpen(@PathParam("tstr") String tstr, Session session){
       String[] str = tstr.split(",");
       
       this.userName = str[0];
       this.ip = str[1];
        this.session = session;
        
        Boolean isIn = false;
        for (WebSocketForJSP socket : WebSocketForJSP.webSocketSet) { 
           if(userName.equals(socket.userName) && ip.equals(socket.ip)){
              isIn = true;
              System.out.println("websocket已經鏈接:"+userName+" "+ip);
              //刪除老的,新增新的
              webSocketSet.remove(socket);
              webSocketSet.add(this);
              break;
           }
        }  
        if(! isIn){
           webSocketSet.add(this);     //加入set中
           System.out.println("有新鏈接加入!當前在線人數爲" + getOnlineCount());
        }
    }

    /**
     * 鏈接關閉調用的方法
     */
    @OnClose
    public void onClose(){
        webSocketSet.remove(this);  //從set中刪除
        System.out.println("有一鏈接關閉!當前在線人數爲" + getOnlineCount());
    }

    /**
     * 收到客戶端消息後調用的方法
     * @param message 客戶端發送過來的消息
     * @param session 可選的參數
     */
    @OnMessage
    public void onMessage(String message, Session session) {
        System.out.println("來自客戶端的消息:" + message);
        /*
        try {
         this.sendMessage("服務器回覆消息:"+this.userName);
      } catch (IOException e) {
         e.printStackTrace();
      }
      */
    }
    
    /**
     * 發生錯誤時調用
     * @param session
     * @param error
     */
    @OnError
    public void onError(Session session, Throwable error){
        System.out.println("發生錯誤");
        this.onClose();
        error.printStackTrace();
    }

    /**
     * 這個方法與上面幾個方法不同。沒有用註解,是根據本身須要添加的方法。
     * @param message
     * @throws IOException
     */
    public void sendMessage(String message) throws IOException{
       System.out.println("返回結果----------------->:"+message);
        this.session.getAsyncRemote().sendText(message);
        //this.session.getAsyncRemote().sendText(message);
    }

    public static synchronized int getOnlineCount() {
        return WebSocketForJSP.webSocketSet.size();
    }
    
}

//而後在用戶登陸的地方判斷便可安全

// 判斷是否已經登陸
      for(WebSocketForJSP item: WebSocketForJSP.webSocketSet){
       if(item.userName.equals(userName)){
          return "用戶已在其餘電腦登陸!";
       }
       String userIp  = IpUtils.getIpAddr(request);
       if(item.ip.equals(userIp)){
          return "同一段IP只容許登錄一個用戶";
       }
      }

客戶端調用服務器

/**
 * 推送 用戶java獲取用戶信息
 */
function sendWebSocketMsg(){
    //判斷當前瀏覽器是否支持WebSocket
// var test = window.location.host;
// var IP = test.split(":");
   var tstr = userName +","+localIP
    if ('WebSocket' in window) {
       //此處參數只容許字符串,不支持json
       websocket = new WebSocket(getRootPath().replace("http","ws")+"/websocket/"+tstr);
    }
    //鏈接發生錯誤的回調方法
    websocket.onerror = function () {
       websocket.close();
    };

    //鏈接成功創建的回調方法
    websocket.onopen = function () {
       //setInterval(function(){
           websocket.send(tstr);
       //}, 10 * 1000);
    }
   //監聽窗口關閉事件,當窗口關閉時,主動去關閉websocket鏈接,防止鏈接還沒斷開就關閉窗口,server端會拋異常。
   window.onbeforeunload = function () {
      websocket.close();
   }
    //接收到消息的回調方法
    websocket.onmessage = function (event) {
       try {
          var result = JSON.parse(event.data);
           // 是不是對象
           if(typeof(result) == "object" && Object.prototype.toString.call(result).toLowerCase() == "[object object]" && !result.length){
              if(result.msgType != null && typeof(result.msgType) != "undefined"){
                 // 負載-自動化運維
                 debugger;
                 window.showScriptDiagle(result);
              }else{
                 debugger;
                 // 回顯健康-運維經驗
                 $(window.frames[0])[0].doScriptFn(result);
              }
           }
      } catch (e) {
         if("logOut" == event.data){
            websocket.close();
            sessionStorage.setItem("oneUser",true);
             location.href = getRootPath()+"/jsps/login/login.jsp";
         }else if("logOutByIp" == event.data){
            websocket.close();
            sessionStorage.setItem("oneIp",true);
             location.href = getRootPath()+"/jsps/login/login.jsp";
         }
      }
       console.log(event.data);
    }

    //鏈接關閉的回調方法
    websocket.onclose = function () {
       websocket.close();
    }
}
相關文章
相關標籤/搜索