初探和實現(xiàn)websocket心跳重連

心跳重連緣由

在使用websocket過程中,可能會出現(xiàn)網(wǎng)絡(luò)斷開的情況昌犹,比如信號不好,或者網(wǎng)絡(luò)臨時性關(guān)閉缚忧,這時候websocket的連接已經(jīng)斷開闪水,
而瀏覽器不會執(zhí)行websocket 的 onclose方法,我們無法知道是否斷開連接持钉,也就無法進行重連操作州刽。
如果當(dāng)前發(fā)送websocket數(shù)據(jù)到后端,一旦請求超時门坷,onclose便會執(zhí)行,這時候便可進行綁定好的重連操作框冀。
因此websocket心跳重連就應(yīng)運而生流椒。

如何實現(xiàn)

在websocket實例化的時候,我們會綁定一些事件:

var ws = new WebSocket(url);
ws.onclose = function () {
    //something
};
ws.onerror = function () {
    //something
};
        
ws.onopen = function () {
   //something
};
ws.onmessage = function (event) {
   //something
}

如果希望websocket連接一直保持明也,我們會在close或者error上綁定重新連接方法宣虾。

ws.onclose = function () {
    reconnect();
};
ws.onerror = function () {
    reconnect();
};

這樣一般正常情況下失去連接時,觸發(fā)onclose方法温数,我們就能執(zhí)行重連了绣硝。

那么針對斷網(wǎng)的情況的心跳重連,怎么實現(xiàn)呢撑刺。
簡單的實現(xiàn):

var heartCheck = {
    timeout: 60000,//60ms
    timeoutObj: null,
    reset: function(){
        clearTimeout(this.timeoutObj);
     this.start();
    },
    start: function(){
        this.timeoutObj = setTimeout(function(){
            ws.send("HeartBeat");
        }, this.timeout)
    }
}

ws.onopen = function () {
   heartCheck.start();
};
ws.onmessage = function (event) {
    heartCheck.reset();
}

如上代碼鹉胖,heartCheck 的 reset和start方法主要用來控制心跳的定時。

什么條件下執(zhí)行心跳:

當(dāng)onopen也就是連接上時,我們便開始start計時甫菠,如果在定時時間范圍內(nèi)挠铲,onmessage獲取到了后端的消息,我們就重置倒計時寂诱,距離上次從后端獲取到消息超過60秒之后拂苹,執(zhí)行心跳檢測,看是不是斷連了痰洒,這個檢測時間可以自己根據(jù)自身情況設(shè)定瓢棒。

判斷前端ws斷開(斷網(wǎng)但不限于斷網(wǎng)的情況):

當(dāng)心跳檢測send方法執(zhí)行之后,如果當(dāng)前websocket是斷開狀態(tài)(或者說斷網(wǎng)了)丘喻,發(fā)送超時之后脯宿,瀏覽器的ws會自動觸發(fā)onclose方法,重連也執(zhí)行了(onclose方法體綁定了重連事件)仓犬,如果當(dāng)前一直是斷網(wǎng)狀態(tài)嗅绰,重連會2秒(時間是自己代碼設(shè)置的)執(zhí)行一次直到網(wǎng)絡(luò)正常后連接成功。

如此一來搀继,我們判斷前端主動斷開ws的心跳檢測就實現(xiàn)了窘面。為什么說是前端主動斷開,因為當(dāng)前這種情況主要是通過前端ws的事件來判斷的叽躯,后面說后端主動斷開的情況财边。

我本想測試websocket超時時間,又發(fā)現(xiàn)了一些新的問題

  1. 在chrome中点骑,如果心跳檢測 也就是websocket實例執(zhí)行send之后酣难,15秒內(nèi)沒發(fā)送到另一接收端,onclose便會執(zhí)行黑滴。那么超時時間是15秒憨募。
  2. 我又打開了Firefox ,F(xiàn)irefox在斷網(wǎng)7秒之后袁辈,直接執(zhí)行onclose菜谣。說明在Firefox中不需要心跳檢測便能自動onclose。
  3. 同一代碼晚缩, reconnect方法 在chrome 執(zhí)行了一次尾膊,F(xiàn)irefox執(zhí)行了兩次。當(dāng)然我們在幾處地方(代碼邏輯處和websocket事件處)綁定了reconnect()

所以保險起見荞彼,我們還是給reconnect()方法加上一個鎖冈敛,保證只執(zhí)行一次

目前來看不同的瀏覽器,有不同的機制鸣皂,無論瀏覽器websocket自身會不會在斷網(wǎng)情況下執(zhí)行onclose抓谴,加上心跳重連后暮蹂,已經(jīng)能保證onclose的正常觸發(fā)。

判斷后端斷開:

如果后端因為一些情況斷開了ws齐邦,是可控情況下的話椎侠,會下發(fā)一個斷連的消息通知,之后才會斷開措拇,我們便會重連我纪。
如果因為一些異常斷開了連接,我們是不會感應(yīng)到的丐吓,所以如果我們發(fā)送了心跳一定時間之后浅悉,后端既沒有返回心跳響應(yīng)消息,前端又沒有收到任何其他消息的話券犁,我們就能斷定后端主動斷開了术健。
一點特別重要的發(fā)送心跳到后端,后端收到消息之后必須返回消息粘衬,否則超過60秒之后會判定后端主動斷開了荞估。再改造下代碼:

var heartCheck = {
    timeout: 60000,//60ms
    timeoutObj: null,
    serverTimeoutObj: null,
    reset: function(){
        clearTimeout(this.timeoutObj);
        clearTimeout(this.serverTimeoutObj);
     this.start();
    },
    start: function(){
        var self = this;
        this.timeoutObj = setTimeout(function(){
            ws.send("HeartBeat");
            self.serverTimeoutObj = setTimeout(function(){
                ws.close();//如果onclose會執(zhí)行reconnect,我們執(zhí)行ws.close()就行了.如果直接執(zhí)行reconnect 會觸發(fā)onclose導(dǎo)致重連兩次
            }, self.timeout)
        }, this.timeout)
    },
}

ws.onopen = function () {
   heartCheck.start();
};
ws.onmessage = function (event) {
    heartCheck.reset();
}
ws.onclose = function () {
    reconnect();
};
ws.onerror = function () {
    reconnect();
};

因為目前我們這種方式會一直重連如果沒連接上或者斷連的話稚新,如果有兩個設(shè)備同時登陸并且會踢另一端下線勘伺,一定要發(fā)送一個踢下線的消息類型,這邊接收到這種類型的消息褂删,邏輯判斷后就不再執(zhí)行reconnect飞醉,否則會出現(xiàn)一只相互擠下線的死循環(huán)。

整理了一個簡單的demo到github屯阀,點擊查看https://github.com/iaiai/websocket

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末缅帘,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子难衰,更是在濱河造成了極大的恐慌钦无,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,755評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件盖袭,死亡現(xiàn)場離奇詭異失暂,居然都是意外死亡,警方通過查閱死者的電腦和手機苍凛,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,305評論 3 395
  • 文/潘曉璐 我一進店門趣席,熙熙樓的掌柜王于貴愁眉苦臉地迎上來兵志,“玉大人醇蝴,你說我怎么就攤上這事∠牒保” “怎么了悠栓?”我有些...
    開封第一講書人閱讀 165,138評論 0 355
  • 文/不壞的土叔 我叫張陵霉涨,是天一觀的道長。 經(jīng)常有香客問我惭适,道長笙瑟,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,791評論 1 295
  • 正文 為了忘掉前任癞志,我火速辦了婚禮往枷,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘凄杯。我一直安慰自己错洁,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,794評論 6 392
  • 文/花漫 我一把揭開白布戒突。 她就那樣靜靜地躺著屯碴,像睡著了一般。 火紅的嫁衣襯著肌膚如雪膊存。 梳的紋絲不亂的頭發(fā)上导而,一...
    開封第一講書人閱讀 51,631評論 1 305
  • 那天,我揣著相機與錄音隔崎,去河邊找鬼今艺。 笑死,一個胖子當(dāng)著我的面吹牛仍稀,可吹牛的內(nèi)容都是我干的洼滚。 我是一名探鬼主播,決...
    沈念sama閱讀 40,362評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼技潘,長吁一口氣:“原來是場噩夢啊……” “哼遥巴!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起享幽,我...
    開封第一講書人閱讀 39,264評論 0 276
  • 序言:老撾萬榮一對情侶失蹤铲掐,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后值桩,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體摆霉,經(jīng)...
    沈念sama閱讀 45,724評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,900評論 3 336
  • 正文 我和宋清朗相戀三年奔坟,在試婚紗的時候發(fā)現(xiàn)自己被綠了携栋。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,040評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡咳秉,死狀恐怖婉支,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情澜建,我是刑警寧澤向挖,帶...
    沈念sama閱讀 35,742評論 5 346
  • 正文 年R本政府宣布蝌以,位于F島的核電站,受9級特大地震影響何之,放射性物質(zhì)發(fā)生泄漏跟畅。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,364評論 3 330
  • 文/蒙蒙 一溶推、第九天 我趴在偏房一處隱蔽的房頂上張望徊件。 院中可真熱鬧,春花似錦蒜危、人聲如沸庇忌。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,944評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽皆疹。三九已至,卻和暖如春占拍,著一層夾襖步出監(jiān)牢的瞬間略就,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,060評論 1 270
  • 我被黑心中介騙來泰國打工晃酒, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留表牢,地道東北人。 一個月前我還...
    沈念sama閱讀 48,247評論 3 371
  • 正文 我出身青樓贝次,卻偏偏與公主長得像崔兴,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子蛔翅,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,979評論 2 355

推薦閱讀更多精彩內(nèi)容

  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,162評論 25 707
  • 帶來兩大好處:1:Header互相溝通的Header是很小的敲茄,大概只有2 Bytes2:Server Push服務(wù)...
    liuboxx1閱讀 478評論 0 2
  • 早上好堰燎,大榕樹 昨夜可看見——無邊黑暗中 一只破舊的老電燈 在風(fēng)雨交加里搖曳 燈光下...
    karller閱讀 281評論 0 0
  • 我們是一家互聯(lián)網(wǎng)公司,前兩天一位同事說要離職钾挟,驚呼平時好好地沒有任何跡象洁灵,突然就說要離職,于是乎把這位同學(xué)拉到會議...
    warston閱讀 1,961評論 2 4
  • 敦煌賦 金漠翡翠等龙,絲路明珠处渣。五千年朗月鑒,三省地龍脈結(jié)蛛砰。枕祁連之雄偉罐栈,帶黨河之雋秀。泉映月牙盈盈泥畅,風(fēng)攜羌笛悠悠荠诬。鳴...
    明白的石頭閱讀 622評論 0 1