移動(dòng)端心跳包

移動(dòng)端心跳包

TCP的心跳機(jī)制

TCP協(xié)議,本身擁有一個(gè)KeepAlive機(jī)制蔓倍,既然有了心跳機(jī)制,為什么還要在應(yīng)用層面設(shè)計(jì)一個(gè)心跳包呢?

  1. TCPKeepAlive機(jī)制的局限, 應(yīng)用層面的可用不等同于網(wǎng)絡(luò)層面連接的存活狀態(tài)

    TCP層面的keepalive存在更多意義上是為了檢測兩端連接是否正常贯被,注重點(diǎn)是在于連接的本身,默認(rèn)TCP的超時(shí)時(shí)間2小時(shí)太長,還會(huì)存在一些讓keep-alive失效的場景

    • keepAlive只能檢測連接存活,而不能檢測連接可用,比如服務(wù)器因?yàn)樨?fù)載過高導(dǎo)致無法響應(yīng)請(qǐng)求但是連接仍然存在暗膜,此時(shí)keepalive無法判斷連接是否可用

    • 如果TCP連接的另一端突然掉線映挂,這個(gè)時(shí)候我們并不知道網(wǎng)絡(luò)已經(jīng)關(guān)閉。而此時(shí)藏鹊,如果有發(fā)送數(shù)據(jù)失敗皮假,TCP會(huì)自動(dòng)進(jìn)行重傳。重傳包的優(yōu)先級(jí)高于keepalive的包衩椒,那就意味著蚌父,我們的keepalive總是不能發(fā)送出去哮兰。 而此時(shí),我們也并不知道該連接已經(jīng)出錯(cuò)而中斷苟弛。在較長時(shí)間的重傳失敗之后喝滞,我們才會(huì)知道。

  2. HTTPKeepAlive機(jī)制:復(fù)用tcp連接

    • HTTP/1.0之前,默認(rèn)使用短連接,每進(jìn)行一次HTTP操作,就簡歷一次連接,但任務(wù)結(jié)束就中斷連接,

    • HTTP/1.1起,默認(rèn)使用長連接,用以保持連接特性,復(fù)用同一個(gè)TCP連接,串行的來完成傳遞請(qǐng)求-響應(yīng)數(shù)據(jù),長連接的優(yōu)勢是節(jié)省了創(chuàng)建連接的耗時(shí)膏秫。

應(yīng)用層面的HeartBeat設(shè)計(jì)

客戶端開啟一個(gè)定時(shí)任務(wù),定時(shí)向已經(jīng)建立連接的服務(wù)端發(fā)送請(qǐng)求(心跳包),服務(wù)端接收到后,就需要處理該特殊請(qǐng)求,返回響應(yīng),如果沒有收到心跳響應(yīng)多次,就認(rèn)為連接不可用,進(jìn)行重連

  • 心跳包的設(shè)計(jì)

    • 定時(shí)任務(wù),頻率設(shè)計(jì)(固定,)

    • 連接閑置才庇以猓活,避免流量浪費(fèi)

    • 重試策略

    • 特定場景的觸發(fā),點(diǎn)亮屏幕,切換前臺(tái)保證信息及時(shí)收到

    • 心跳間隔要小于NAT超時(shí)時(shí)間

MQTT Android心跳包 AlarmPingSender

  • 定義了一個(gè)心跳包發(fā)送接口
  public void init();
  //開發(fā)發(fā)送心跳包
  public void start();
  //停止發(fā)送心跳包,可能是出錯(cuò),獲取連接關(guān)閉
  public void stop();
  //下一次心跳包的發(fā)送
  public void schedule(long delayInMilliseconds);
  • Android端 心跳包實(shí)現(xiàn)類
private MqttService service = mqttService;
    ?
    public void start() {
     String action = "mqtt_heart_beat"
     //注冊(cè)上對(duì)應(yīng)廣播接收器
     service.registerReceiver(alarmReceiver, new IntentFilter(action));
     //準(zhǔn)備好 PendingIntent,每次都是定時(shí)發(fā)送一個(gè)廣播
     pendingIntent = PendingIntent.getBroadcast(service, 0, 
     new Intent(action), PendingIntent.FLAG_UPDATE_CURRENT);
     //設(shè)置好下一次心跳包的發(fā)送
     schedule(interval_time);
    }
    //準(zhǔn)備好下一次心跳
    public void schedule(long delayInMilliseconds) {
     //下一次心跳時(shí)間
     long nextAlarmInMilliseconds = System.currentTimeMillis()
     + delayInMilliseconds;
     //獲取alarmManager
     AlarmManager alarmManager = (AlarmManager) service
     .getSystemService(Service.ALARM_SERVICE);

     //AlaramManager的兼容處理 定時(shí)任務(wù)
     if(Build.VERSION.SDK_INT >= 23){
     alarmManager.setExactAndAllowWhileIdle(
     AlarmManager.RTC_WAKEUP,nextAlarmInMilliseconds,pendingIntent);
     } else if (Build.VERSION.SDK_INT >= 19) {
     alarmManager.setExact(
     AlarmManager.RTC_WAKEUP,nextAlarmInMilliseconds,pendingIntent);
     } else {
     alarmManager.set(                            AlarmManager.RTC_WAKEUP,nextAlarmInMilliseconds,pendingIntent);
     }
     }
    ?

    //停止定時(shí)任務(wù)
    public void stop() {
     AlarmManager alarmManager = (AlarmManager)service.getSystemService(Service.ALARM_SERVICE);
     alarmManager.cancel(pendingIntent);
    }
    ?
    class AlarmReceiver extends BroadcastReceiver {
     private WakeLock wakelock;

     public void onReceive(Context context, Intent intent) {
     //AlaramManager持有的cpu wake_lock只能保證onReciver方法執(zhí)行完成,但是我們需要在此處發(fā)送心跳包等,所以需要?jiǎng)?chuàng)建一個(gè)新的wake_lock
     PowerManager pm = (PowerManager) service
     .getSystemService(Service.POWER_SERVICE);
     wakelock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, wakeLockTag);
     wakelock.acquire();
    ?
     //心跳包處理相關(guān)
     IMqttToken token = comms.checkForActivity();
     wakelock.release();

     }
     }
    // ClientComms#checkForActivity -> ClientStat#checkForActivity
    public MqttToken checkForActivity() {
     //將pingComond加入到發(fā)送數(shù)據(jù)流中
     pendingFlows.insertElementAt(pingCommand, 0);
     //獲取下次心跳包時(shí)間
     nextPingTime = getKeepAlive();
     //準(zhǔn)備下一次心跳包的發(fā)送
     pingSender.schedule(nextPingTime);
    }

附錄:

  • NAT超時(shí)

    • 因?yàn)?IP v4IP量有限,運(yùn)營商分配給手機(jī)終端的 IP是運(yùn)營商內(nèi)網(wǎng)的IP缤削,手機(jī)要連接Internet窘哈,就需要通過運(yùn)營商的網(wǎng)關(guān)做一個(gè)網(wǎng)絡(luò)地址轉(zhuǎn)換(Network Address TranslationNAT)亭敢。簡單的說運(yùn)營商的網(wǎng)關(guān)需要維護(hù)一個(gè)外網(wǎng)IP滚婉、端口到內(nèi)網(wǎng) IP、端口的對(duì)應(yīng)關(guān)系吨拗,以確保內(nèi)網(wǎng)的手機(jī)可以跟Internet的服務(wù)器通訊满哪。
    • 大部分移動(dòng)無線網(wǎng)絡(luò)運(yùn)營商都在鏈路一段時(shí)間沒有數(shù)據(jù)通訊時(shí)婿斥,會(huì)淘汰 NAT表中的對(duì)應(yīng)項(xiàng)劝篷,造成鏈路中斷。
    • 長連接心跳間隔必須要小于NAT超時(shí)時(shí)間(aging-time)民宿,如果超過aging-time不做心跳娇妓,TCP長連接鏈路就會(huì)中斷,Server就無法發(fā)送Push給手機(jī)活鹰,只能等到客戶端下次心跳失敗后哈恰,重建連接才能取到消息。

思考

  • 心跳機(jī)制保證了連接的可用性,保證推送信息的及時(shí)收取,但是為了及時(shí)收到信息,敝救海活進(jìn)程也是一個(gè)逃不開的手段,后續(xù)分析一下,進(jìn)程的弊疟粒活的手段

參考鏈接

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末荠医,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子桑涎,更是在濱河造成了極大的恐慌彬向,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,126評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件攻冷,死亡現(xiàn)場離奇詭異娃胆,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)等曼,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,254評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門里烦,熙熙樓的掌柜王于貴愁眉苦臉地迎上來凿蒜,“玉大人,你說我怎么就攤上這事胁黑「莩蹋” “怎么了?”我有些...
    開封第一講書人閱讀 152,445評(píng)論 0 341
  • 文/不壞的土叔 我叫張陵别厘,是天一觀的道長虱饿。 經(jīng)常有香客問我,道長触趴,這世上最難降的妖魔是什么氮发? 我笑而不...
    開封第一講書人閱讀 55,185評(píng)論 1 278
  • 正文 為了忘掉前任,我火速辦了婚禮冗懦,結(jié)果婚禮上爽冕,老公的妹妹穿的比我還像新娘。我一直安慰自己披蕉,他們只是感情好颈畸,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,178評(píng)論 5 371
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著没讲,像睡著了一般眯娱。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上爬凑,一...
    開封第一講書人閱讀 48,970評(píng)論 1 284
  • 那天徙缴,我揣著相機(jī)與錄音,去河邊找鬼嘁信。 笑死于样,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的潘靖。 我是一名探鬼主播穿剖,決...
    沈念sama閱讀 38,276評(píng)論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢(mèng)啊……” “哼卦溢!你這毒婦竟也來了糊余?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 36,927評(píng)論 0 259
  • 序言:老撾萬榮一對(duì)情侶失蹤既绕,失蹤者是張志新(化名)和其女友劉穎啄刹,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體凄贩,經(jīng)...
    沈念sama閱讀 43,400評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡誓军,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,883評(píng)論 2 323
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了疲扎。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片昵时。...
    茶點(diǎn)故事閱讀 37,997評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡捷雕,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出壹甥,到底是詐尸還是另有隱情救巷,我是刑警寧澤,帶...
    沈念sama閱讀 33,646評(píng)論 4 322
  • 正文 年R本政府宣布句柠,位于F島的核電站浦译,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏溯职。R本人自食惡果不足惜精盅,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,213評(píng)論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望谜酒。 院中可真熱鬧叹俏,春花似錦、人聲如沸僻族。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,204評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽述么。三九已至蝌数,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間碉输,已是汗流浹背籽前。 一陣腳步聲響...
    開封第一講書人閱讀 31,423評(píng)論 1 260
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留敷钾,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 45,423評(píng)論 2 352
  • 正文 我出身青樓肄梨,卻偏偏與公主長得像阻荒,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子众羡,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,722評(píng)論 2 345