WebSocket 心跳 登陸 實(shí)例代碼!

· JS-前端代碼.

var websocket;//websocket實(shí)例
var lockReconnect = false;//避免重復(fù)連接
var userno="123";

var wsUrl = "ws://localhost:8080/test/websocket/"+userno;

function createWebSocket(url) {
    try {
        websocket = new WebSocket(url);
        initEventHandle();
    } catch (e) {
        reconnect(url);
    }     
}

function initEventHandle() {
    websocket.onclose = function () {
        console.log("WebSocket連接已經(jīng)關(guān)閉");
        reconnect(wsUrl);
    };
    websocket.onerror = function () {
        console.log("WebSocket連接發(fā)生錯(cuò)誤");
        reconnect(wsUrl);
    };
    websocket.onopen = function () {
        console.log("WebSocket連接已經(jīng)成功");
        //心跳檢測重置
        heartCheck.reset().start();
    };
    websocket.onmessage = function (event) {
        setMessageInnerHTML(event.data);
        //如果獲取到消息,心跳檢測重置
        //拿到任何消息都說明當(dāng)前連接是正常的
        heartCheck.reset().start();
    }
}

//重新連接webSocket
function reconnect(url) {
    if(lockReconnect) return;
    lockReconnect = true;
    //沒連接上會(huì)一直重連卓鹿,設(shè)置延遲避免請(qǐng)求過多
    setTimeout(function () {
        createWebSocket(url);
        lockReconnect = false;
    }, 2000);
}

//心跳檢測
var heartCheck = {
    timeout: 60000,//60秒
    timeoutObj: null,
    serverTimeoutObj: null,
    reset: function(){
        clearTimeout(this.timeoutObj);
        clearTimeout(this.serverTimeoutObj);
        return this;
    },
    start: function(){
        var self = this;
        this.timeoutObj = setTimeout(function(){
            //這里發(fā)送一個(gè)心跳,后端收到后周瞎,返回一個(gè)心跳消息,
            //onmessage拿到返回的心跳就說明連接正常
            websocket.send("HeartBeat");
            self.serverTimeoutObj = setTimeout(function(){//如果超過一定時(shí)間還沒重置胁黑,說明后端主動(dòng)斷開了
                websocket.close();//如果onclose會(huì)執(zhí)行reconnect职烧,我們執(zhí)行ws.close()就行了.如果直接執(zhí)行reconnect 會(huì)觸發(fā)onclose導(dǎo)致重連兩次
            }, self.timeout)
        }, this.timeout)
    }
}
//判斷當(dāng)前瀏覽器是否支持WebSocket
if ('WebSocket' in window) {
    //初始化連接webSocket
    createWebSocket(wsUrl);
}
else {
    alert('當(dāng)前瀏覽器 Not support websocket')
}

//將消息顯示在網(wǎng)頁上
function setMessageInnerHTML(innerHTML) {
    console.log(innerHTML);
    var data = JSON.parse(innerHTML);
    console.log("-------------- websocket -----------------------------------");
    
}

//關(guān)閉WebSocket連接
function closeWebSocket() {
    websocket.close();
}

//發(fā)送消息
function send(message) {
    websocket.send(message);
}

· JAVA-后端代碼.

package com.ay.websocket;


import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.concurrent.ConcurrentHashMap;


@ServerEndpoint("/websocket/{userno}")
public class WebSocket {
    //靜態(tài)變量,用來記錄當(dāng)前在線連接數(shù)邓梅。應(yīng)該把它設(shè)計(jì)成線程安全的。
    private static int onlineCount = 0;
    //concurrent包的線程安全Set邑滨,用來存放每個(gè)客戶端對(duì)應(yīng)的MyWebSocket對(duì)象日缨。若要實(shí)現(xiàn)服務(wù)端與單一客戶端通信的話,可以使用Map來存放掖看,其中Key可以為用戶標(biāo)識(shí)
    private static ConcurrentHashMap<String, WebSocket> webSocketSet = new ConcurrentHashMap<String, WebSocket>();
    //與某個(gè)客戶端的連接會(huì)話匣距,需要通過它來給客戶端發(fā)送數(shù)據(jù)
    private Session session;
    //當(dāng)前發(fā)消息的人員編號(hào)
    private String userno = "";

    /**
     * 連接建立成功調(diào)用的方法
     *
     * @param session 可選的參數(shù)面哥。session為與某個(gè)客戶端的連接會(huì)話,需要通過它來給客戶端發(fā)送數(shù)據(jù)
     */
    @OnOpen
    public void onOpen(@PathParam(value = "userno") String param, Session session, EndpointConfig config) {
        System.out.println(param);
        userno = param;//接收到發(fā)送消息的人員編號(hào)
        this.session = session;
        webSocketSet.put(param, this);//加入map中
        addOnlineCount();           //在線數(shù)加1
        System.out.println("有新連接加入毅待!當(dāng)前在線人數(shù)為" + getOnlineCount());
    }

    /**
     * 連接關(guān)閉調(diào)用的方法
     */
    @OnClose
    public void onClose() {
        if (!userno.equals("")) {
            webSocketSet.remove(userno);  //從set中刪除
            subOnlineCount();           //在線數(shù)減1
            System.out.println("有一連接關(guān)閉尚卫!當(dāng)前在線人數(shù)為" + getOnlineCount());
        }
    }

    /**
     * 收到客戶端消息后調(diào)用的方法
     *
     * @param message 客戶端發(fā)送過來的消息
     * @param session 可選的參數(shù)
     */
    @SuppressWarnings("unused")
//  @OnMessage
    public void onMessage(String message, Session session) {
        System.out.println("來自客戶端的消息:" + message);
//        session.get
        //群發(fā)消息
        if (1 < 2) {
            sendAll(message);
        } else {
            //給指定的人發(fā)消息
            sendToUser(message);
        }
    }

    /**
     * 給指定的人發(fā)送消息
     * @param message
     */
    @OnMessage
    public void sendToUser(String message) {
        String sendUserno = message.split("[|]")[1];
        String sendMessage = message.split("[|]")[0];
        String now = getNowTime();
        try {
            if (webSocketSet.get(sendUserno) != null) {
                webSocketSet.get(sendUserno).sendMessage(now + "用戶" + userno + "發(fā)來消息:" + " <br/> " + sendMessage);
            } else {
                System.out.println("當(dāng)前用戶不在線");
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 給所有人發(fā)消息
     * @param message
     */
    private void sendAll(String message) {
        String now = getNowTime();
        String sendMessage = message.split("[|]")[0];
        //遍歷HashMap
        for (String key : webSocketSet.keySet()) {
            try {
                //判斷接收用戶是否是當(dāng)前發(fā)消息的用戶
                if (!userno.equals(key)) {
                    webSocketSet.get(key).sendMessage(now + "用戶" + userno + "發(fā)來消息:" + " <br/> " + sendMessage);
                    System.out.println("key = " + key);
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }


    /**
     * 獲取當(dāng)前時(shí)間
     *
     * @return
     */
    private String getNowTime() {
        Date date = new Date();
        DateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String time = format.format(date);
        return time;
    }
    /**
     * 發(fā)生錯(cuò)誤時(shí)調(diào)用
     *
     * @param session
     * @param error
     */
    @OnError
    public void onError(Session session, Throwable error) {
        System.out.println("發(fā)生錯(cuò)誤");
        error.printStackTrace();
    }

    /**
     * 這個(gè)方法與上面幾個(gè)方法不一樣。沒有用注解尸红,是根據(jù)自己需要添加的方法吱涉。
     *
     * @param message
     * @throws IOException
     */
    public void sendMessage(String message) throws IOException {
        this.session.getBasicRemote().sendText(message);
        //this.session.getAsyncRemote().sendText(message);
    }

    public static synchronized int getOnlineCount() {
        return onlineCount;
    }

    public static synchronized void addOnlineCount() {
        WebSocket.onlineCount++;
    }

    public static synchronized void subOnlineCount() {
        WebSocket.onlineCount--;
    }




    public static void send2User(String sendUserno,String sendMessage){
        try {
            if (webSocketSet.get(sendUserno) != null) {
                webSocketSet.get(sendUserno).sendMessage(sendMessage);
            } else {
                System.out.println("當(dāng)前用戶不在線");
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }


    /**
     * 給所有人發(fā)消息
     * @param message
     */
    public static void sendAlls(String message) {

        String sendMessage = message.split("[|]")[0];
        //遍歷HashMap
        for (String key : webSocketSet.keySet()) {
            try {
                //判斷接收用戶是否是當(dāng)前發(fā)消息的用戶
                webSocketSet.get(key).sendMessage(sendMessage);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }


}

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市外里,隨后出現(xiàn)的幾起案子怎爵,更是在濱河造成了極大的恐慌,老刑警劉巖盅蝗,帶你破解...
    沈念sama閱讀 217,185評(píng)論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件鳖链,死亡現(xiàn)場離奇詭異,居然都是意外死亡风科,警方通過查閱死者的電腦和手機(jī)撒轮,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,652評(píng)論 3 393
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來贼穆,“玉大人,你說我怎么就攤上這事兰粉」嗜” “怎么了?”我有些...
    開封第一講書人閱讀 163,524評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵玖姑,是天一觀的道長愕秫。 經(jīng)常有香客問我,道長焰络,這世上最難降的妖魔是什么戴甩? 我笑而不...
    開封第一講書人閱讀 58,339評(píng)論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮闪彼,結(jié)果婚禮上甜孤,老公的妹妹穿的比我還像新娘。我一直安慰自己畏腕,他們只是感情好缴川,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,387評(píng)論 6 391
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著描馅,像睡著了一般把夸。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上铭污,一...
    開封第一講書人閱讀 51,287評(píng)論 1 301
  • 那天恋日,我揣著相機(jī)與錄音膀篮,去河邊找鬼。 笑死岂膳,一個(gè)胖子當(dāng)著我的面吹牛各拷,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播闷营,決...
    沈念sama閱讀 40,130評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼烤黍,長吁一口氣:“原來是場噩夢(mèng)啊……” “哼!你這毒婦竟也來了傻盟?” 一聲冷哼從身側(cè)響起速蕊,我...
    開封第一講書人閱讀 38,985評(píng)論 0 275
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎娘赴,沒想到半個(gè)月后规哲,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,420評(píng)論 1 313
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡诽表,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,617評(píng)論 3 334
  • 正文 我和宋清朗相戀三年唉锌,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片竿奏。...
    茶點(diǎn)故事閱讀 39,779評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡袄简,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出泛啸,到底是詐尸還是另有隱情绿语,我是刑警寧澤,帶...
    沈念sama閱讀 35,477評(píng)論 5 345
  • 正文 年R本政府宣布候址,位于F島的核電站吕粹,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏岗仑。R本人自食惡果不足惜匹耕,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,088評(píng)論 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望荠雕。 院中可真熱鬧稳其,春花似錦、人聲如沸舞虱。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,716評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽矾兜。三九已至损趋,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背浑槽。 一陣腳步聲響...
    開封第一講書人閱讀 32,857評(píng)論 1 269
  • 我被黑心中介騙來泰國打工蒋失, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人桐玻。 一個(gè)月前我還...
    沈念sama閱讀 47,876評(píng)論 2 370
  • 正文 我出身青樓篙挽,卻偏偏與公主長得像,于是被迫代替她去往敵國和親镊靴。 傳聞我的和親對(duì)象是個(gè)殘疾皇子铣卡,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,700評(píng)論 2 354