1. 程式人生 > >WebSocket,實現簡單的廣播功能

WebSocket,實現簡單的廣播功能

改變現在,從通訊開始

傳統的前端和後端的資料互動是使用輪詢方法,會佔用大量資源。在如今高速發展的時代,一種能提升效率的方法或者說新技術便顯得尤為重要。
websocket便是這樣一種技術,有關於它的更多的一些細節,大家可以自行百度。(本部落格部分程式碼來源自網上,向前輩們致敬)
這裡看一下廣播的演示結果:
這裡寫圖片描述

不寫程式碼,終究是紙上談兵

這裡只是展示websocket的一個小demo,並未對介面做過多要求。於是只設計了一個簡單的傳送訊息文字框和按鈕。載入頁面時初始化socket,點選按鈕觸發socket.send(msg)方法便可。由於是多客戶端廣播,每一個socket在連線伺服器時需要加上自己相應的id引數。(這裡生成id引數方法並不推薦)

<%-- Created by IntelliJ IDEA. --%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<!DOCTYPE html>
<html>

<head>
  <meta name="viewport" content="width=device-width" />
  <title>WebSocket 客戶端</title>
</head>

<body>
<div
>
<div class="main"> <input name="message" id="msg" onkeydown="if (event.keyCode==13) sendMsg()"/> <button onclick="sendMsg()">傳送</button> </div> </div> <script src="resource/js/jquery.js" type="text/javascript" charset="utf-8"></script> <script
src="resource/js/socket.js" type="text/javascript" charset="utf-8">
</script> <script type="text/javascript"> var uid = getRandomWithoutRepeat([1,2,3,4,5,6,7,8,9,10]);//獲取當前賬戶的id; var url="ws://127.0.0.1:8080/webSocketServer/"+uid[0]; var socket = getSocket(url); bindMethod(socket); function sendMsg() { Log("傳送:"+$("#msg").val(),"INFO"); socket.send($("#msg").val()); $("#msg").val("") } window.onbeforeunload = function() { socket.close(); }; /** * 建立隨機數 * @param Min * @param Max * @returns {*} * @constructor */ function getRandom(Min,Max){ var Range = Max - Min; var Rand = Math.random(); return(Min + Math.round(Rand * Range)); } /** * 獲取不重複的隨機數 * @param arr * @returns {Array} */ function getRandomWithoutRepeat(arr){ var temp=[]; //temp存放生成的隨機陣列 for (var i=0;i<arr.length;i++) { var num=Math.floor(Math.random()*arr.length); //生成隨機數num temp.push(arr[num]); //獲取arr[num]並放入temp arr.splice(num,1); } return temp; } </script> </body> </html>

可以發現上述介面部分引入了socket.js檔案,這個是我自己抽象出來的一部分可供重用的方法部分,比如說列印日誌和建立websocket的程式碼。

/**
 * Created by zipple on 2017/9/28.
 * 建立web socket 物件
 * 定義相關方法
 */


/**
 * 建立socket物件
 * @param url
 * @returns {WebSocket}
 */
function getSocket(url) {
    if(typeof(WebSocket) == "undefined") { //此處判斷支援Android
        alert("您的瀏覽器不支援WebSocket");
    }
    Log("建立socket物件","OK");
    return new WebSocket(url);
}
/**
 * 為建立的socket物件繫結相關方法
 * @param ws
 * @param elements 獲取資訊的地方
 */
function bindMethod(ws) {
    ws.onopen = function () {
      Log("連線成功","OK")
    };
    ws.onmessage = WSonMessage;
    ws.onclose = WSonClose;
    ws.onerror = WSonError;
}
/**
 * 獲取資料
 * @param event
 */
function WSonMessage(event) {
    Log("獲取到資訊:"+event.data,"OK");
    var div = "<div>"+event.data+"</div>";
    $("body").prepend($(div))
}
/**
 * 關閉連線
 */
function WSonClose() {
    Log("連線關閉。", "ERROR");
}

/**
 * 連結異常
 */
function WSonError() {
    Log("WebSocket錯誤。", "ERROR");
}

/**
 * 在控制檯列印資料
 * @param msg
 * @param type
 */
function Log(msg,type) {
    switch (type){
        case 0 :
            type="ERROR";
            break;
        case 1:
            type="OK";
            break;
        case 2:
            type="WARNING";
            break;
        default:
            type="INFO"
    }
    console.log(type+":"+msg+" at "+getNowFormatDate());
}

/**
 * 獲取系統當前時間
 * @returns {string}
 */
function getNowFormatDate() {
    var currentdate="error occurred in getNoeFormatDate";
    var date = new Date();
    var seperator1 = "-";
    var seperator2 = ":";
    var month = date.getMonth() + 1;
    var strDate = date.getDate();
    if (month >= 1 && month <= 9) {
        month = "0" + month;
    }
    if (strDate >= 0 && strDate <= 9) {
        strDate = "0" + strDate;
    }
    currentdate = date.getFullYear() + seperator1 + month + seperator1 + strDate
        + " " + date.getHours() + seperator2 + date.getMinutes()
        + seperator2 + date.getSeconds();
    return currentdate;
}

後臺:接收連線請求,儲存session,遍歷物件,轉發msg

為了實現使用者的廣播(即將某個使用者傳送到伺服器端的資訊轉發至所有使用者)功能,我們需要在接收到使用者websocket連線請求時儲存當前使用者的session,用於轉發資料。
因為這只是一個簡單的demo入門,便不再考慮其他的相關安全操作,下線判斷等等。

package webSocket;



import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.CopyOnWriteArraySet;

import javax.websocket.OnClose;
import javax.websocket.OnError;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;

/**
 * 多個使用者之間的通訊
 */
@ServerEndpoint("/webSocketServer/{userId}")
public class WebSocketServer {

    private Session session;
    private static CopyOnWriteArraySet<WebSocketServer> webSocketSet = new CopyOnWriteArraySet<>();


    /**
     * 連線建立成功呼叫的方法
     * @param session  可選的引數。session為與某個客戶端的連線會話,需要通過它來給客戶端傳送資料
     */
    @OnOpen
    public void onOpen(@PathParam("userId") String userId,Session session){
        System.out.println("Client connected  "+userId);//在這裡儲存使用者
        this.session =session;
        webSocketSet.add(this);
    }

    /**
     * 連線關閉呼叫的方法
     */
    @OnClose
    public void onClose(@PathParam("userId") String userId){
        System.out.println("Connection closed");
    }

    /**
     * 收到客戶端訊息後呼叫的方法
     * @param message 客戶端傳送過來的訊息
     */
    @OnMessage
    public void onMessage(@PathParam("userId") String userId,String message) throws IOException {
        System.out.println("伺服器接收使用者"+userId+"訊息: " + message);


        for (WebSocketServer ws: webSocketSet){
            ws.session.getBasicRemote().sendText("伺服器回覆:"+message);
        }

    }

    /**
     * 發生錯誤時呼叫
     * @param session
     * @param error
     */
    @OnError
    public void onError(Session session, Throwable error){
        error.printStackTrace();
    }
}

好吧!
其實是寫這篇部落格的時候太困了!
堅持不住了,就直接把所有原始碼貼上來了。
沒有做過多解釋,請同行見諒。

你逃避的北上廣,是我曾嚮往過的遠方