百度統(tǒng)一socket長(zhǎng)連接組件從0到1的技術(shù)實(shí)踐

本文由百度消息中臺(tái)團(tuán)隊(duì)分享,引用自百度Geek說(shuō),原題“百度iOS端長(zhǎng)連接組件建設(shè)及應(yīng)用實(shí)踐”,為了幫助理解,本文有修訂和改動(dòng)。
1、引言
在過(guò)去的十年里,移動(dòng)端互聯(lián)網(wǎng)技術(shù)飛速發(fā)展,移動(dòng)應(yīng)用逐漸成為主要的便捷訪問(wèn)和使用互聯(lián)網(wǎng)的方式,它們承接了越來(lái)越多的業(yè)務(wù)和功能,這也意味著對(duì)移動(dòng)端和服務(wù)器之間的通信效率和穩(wěn)定性提出了更高的要求。
為了實(shí)現(xiàn)更高效的實(shí)時(shí)通信和數(shù)據(jù)同步,socket實(shí)時(shí)長(zhǎng)連接逐漸成為一種關(guān)鍵技術(shù),它通過(guò)維持客戶端和服務(wù)器之間的持久連接,實(shí)現(xiàn)了雙方實(shí)時(shí)數(shù)據(jù)交換,避免了頻繁的建連和斷連開(kāi)銷,從而提高用戶體驗(yàn)、服務(wù)穩(wěn)定性、可靠性等方面的表現(xiàn)。
本文旨在探討socket長(zhǎng)連接技術(shù)在移動(dòng)端的實(shí)踐,并以iOS端為例,重點(diǎn)分享了百度在實(shí)現(xiàn)統(tǒng)一socket長(zhǎng)連接組件過(guò)程中的技術(shù)選型和整體架構(gòu)設(shè)計(jì)邏輯。并結(jié)合IM即時(shí)通訊聊天應(yīng)用案例,展示長(zhǎng)連接組件是如何在移動(dòng)應(yīng)用領(lǐng)域?yàn)轭愃茦I(yè)務(wù)場(chǎng)景提供解決方案的。

?技術(shù)交流:
- 移動(dòng)端IM開(kāi)發(fā)入門(mén)文章:《新手入門(mén)一篇就夠:從零開(kāi)發(fā)移動(dòng)端IM》
- 開(kāi)源IM框架源碼:https://github.com/JackJiang2011/MobileIMSDK(備用地址點(diǎn)此)
(本文已同步發(fā)布于:http://www.52im.net/thread-4359-1-1.html)
2、內(nèi)容導(dǎo)讀
本文將分為五個(gè)主要部分。
首先:對(duì)長(zhǎng)連接技術(shù)進(jìn)行概述,包括定義、與短連接的對(duì)比以及在移動(dòng)互聯(lián)網(wǎng)領(lǐng)域的常見(jiàn)應(yīng)用。
接下來(lái):會(huì)簡(jiǎn)單介紹百度長(zhǎng)連接服務(wù),包括搭建的背景以及建成后提供的服務(wù)核心主流程。
然后:將重點(diǎn)討論百度iOS端長(zhǎng)連接SDK搭建過(guò)程中的挑戰(zhàn)和解決方案,包含協(xié)議的選擇、DNS解析優(yōu)化、長(zhǎng)連接?;顧C(jī)制的設(shè)計(jì)等。
緊接著:以IM即時(shí)通訊場(chǎng)景中的長(zhǎng)連接實(shí)踐為例,展示了長(zhǎng)連接SDK是如何為業(yè)務(wù)實(shí)現(xiàn)請(qǐng)求數(shù)據(jù)轉(zhuǎn)發(fā)、接收服務(wù)器主動(dòng)推送等功能的。
最后:對(duì)本文的主要內(nèi)容做了總結(jié),以及對(duì)長(zhǎng)連接在移動(dòng)端應(yīng)用中未來(lái)的發(fā)展趨勢(shì)和前景進(jìn)行了展望。
3、什么是長(zhǎng)連接
長(zhǎng)連接(準(zhǔn)確地說(shuō)是socket長(zhǎng)連接),是指在一個(gè)連接上可以連續(xù)發(fā)送多個(gè)數(shù)據(jù)包,且在連接保持期間,如果沒(méi)有數(shù)據(jù)包發(fā)送,需要雙方發(fā)鏈路檢測(cè)包。
以下是對(duì)長(zhǎng)連接特征的總結(jié):

長(zhǎng)連接與短連接對(duì)比:

長(zhǎng)連接在移動(dòng)互聯(lián)網(wǎng)領(lǐng)域有廣泛的應(yīng)用,特別是在實(shí)現(xiàn)實(shí)時(shí)通信和消息推送等功能方面發(fā)揮了關(guān)鍵作用。
例如:常見(jiàn)的微信、QQ這樣的IM即時(shí)通信軟件,就是通過(guò)維持客戶端和服務(wù)器的長(zhǎng)連接,實(shí)現(xiàn)即時(shí)傳輸信息的需求。
又如:一些網(wǎng)絡(luò)游戲、定位服務(wù)、新聞推送等,也會(huì)使用長(zhǎng)連接,實(shí)時(shí)推送新的動(dòng)態(tài)或者消息給用戶。這樣,無(wú)論用戶在何時(shí)何地,只要連接到互聯(lián)網(wǎng),就能夠接收到最新的信息,極大地提升了使用者的體驗(yàn)度并且使得移動(dòng)互聯(lián)網(wǎng)更加便捷。
總的來(lái)說(shuō):對(duì)實(shí)時(shí)性、數(shù)據(jù)傳輸效率、頻繁通信等有強(qiáng)需求的應(yīng)用,長(zhǎng)連接都是一個(gè)好的選擇。
4、百度設(shè)計(jì)統(tǒng)一長(zhǎng)連接的技術(shù)背景
此前,百度移動(dòng)端都是由各業(yè)務(wù)自運(yùn)維的長(zhǎng)連接,往往搭建和維護(hù)成本都偏高,且可復(fù)用性不大,因此計(jì)劃實(shí)現(xiàn)一套高并發(fā)、低時(shí)延、高觸達(dá)的統(tǒng)一長(zhǎng)連接組件,能夠更靈活高效地支持各業(yè)務(wù)接入,能夠?qū)Π俣认档母鰽PP獨(dú)立輸出長(zhǎng)連接服務(wù)滿足各業(yè)務(wù)的訴求,從而提升服務(wù)質(zhì)量,降低資源成本。
5、百度長(zhǎng)連接服務(wù)主流程
百度長(zhǎng)連接服務(wù)包含兩個(gè)部分:
1)客戶端的長(zhǎng)連接SDK;
2)服務(wù)端的長(zhǎng)連接接入層。
長(zhǎng)連接接入層又包含訪問(wèn)控制模塊和接入模塊,負(fù)責(zé)維護(hù)長(zhǎng)連接管理及業(yè)務(wù)數(shù)據(jù)轉(zhuǎn)發(fā)。

上圖描述了以下內(nèi)容:
1)長(zhǎng)連接建連及心跳?;钸^(guò)程;
2)業(yè)務(wù)登錄和登錄后推送過(guò)程;
3)最終長(zhǎng)連接SDK觸發(fā)斷連的過(guò)程。
下文將以iOS端為例,針對(duì)長(zhǎng)連接SDK的具體實(shí)現(xiàn)解決方案和長(zhǎng)連接SDK在百度APP中的業(yè)務(wù)應(yīng)用落地進(jìn)行更為詳細(xì)的探討。
6、搭建統(tǒng)一長(zhǎng)連接組件的技術(shù)挑戰(zhàn)點(diǎn)
客戶端從0到1搭建一套完整的socket長(zhǎng)連接SDK,這個(gè)過(guò)程涉及到多個(gè)技術(shù)點(diǎn)的考慮。
包括但不限于:
1)連接的創(chuàng)建和維護(hù);
2)網(wǎng)絡(luò)協(xié)議的選擇;
3)使用加密傳輸;
4)驗(yàn)證數(shù)據(jù)來(lái)源等方式保證長(zhǎng)連接的安全性;
5)通過(guò)數(shù)據(jù)傳輸格式選擇、數(shù)據(jù)壓縮等方式減少數(shù)據(jù)量提高傳輸效率;
6)錯(cuò)誤異常處理機(jī)制。
需要開(kāi)發(fā)者根據(jù)實(shí)際情況進(jìn)行最優(yōu)實(shí)現(xiàn)方案的選擇。
在這之中,最核心的技術(shù)難點(diǎn)可以拆解為以下兩部分:
1)連接的創(chuàng)建;
2)連接的維護(hù)。
對(duì)連接的創(chuàng)建,具體來(lái)說(shuō)是:
1)完整建連流程的設(shè)計(jì);
2)網(wǎng)絡(luò)協(xié)議的選擇;
3)設(shè)計(jì)時(shí)需要考慮長(zhǎng)連接建連的成功率、時(shí)延等核心指標(biāo)。
對(duì)于連接的維護(hù),保證建連成功是第一步,長(zhǎng)連接還需要保持維護(hù)雙方連接才可達(dá)成持續(xù)通信的目的。
這包括:
1)在長(zhǎng)時(shí)間無(wú)數(shù)據(jù)交互的情況下,需要定期發(fā)送心跳包進(jìn)行連接的?;?;
2)長(zhǎng)連接連接斷開(kāi)后需要及時(shí)進(jìn)行斷線重連恢復(fù)連接在線狀態(tài)。
7、核心技術(shù)邏輯1:連接的創(chuàng)建
7.1概述
長(zhǎng)連接建連,即客戶端與服務(wù)器建立連接,是長(zhǎng)連接SDK要做的第一件事,所有業(yè)務(wù)方數(shù)據(jù)的傳輸(上下行)都要基于長(zhǎng)連接建連成功的這個(gè)前提。
長(zhǎng)連接建連并不是一個(gè)單一簡(jiǎn)單的操作,而是一個(gè)分階段進(jìn)行的過(guò)程。
本小節(jié)將主要討論在設(shè)計(jì)開(kāi)發(fā)長(zhǎng)連接建連模塊之前,需要重點(diǎn)考慮確認(rèn)的幾個(gè)技術(shù)點(diǎn)和實(shí)現(xiàn)方案,以及百度長(zhǎng)連接SDK最終實(shí)現(xiàn)的長(zhǎng)連接建連完整過(guò)程的架構(gòu)(以iOS端為例)。
7.2挑戰(zhàn)①:協(xié)議的選擇(UDP還是TCP?)
對(duì)于網(wǎng)絡(luò)編程這個(gè)話題,使用哪種數(shù)據(jù)傳輸層協(xié)議來(lái)實(shí)現(xiàn)通信是一個(gè)非常基礎(chǔ)但一直爭(zhēng)論不休的問(wèn)題。
UDP和TCP各有各的應(yīng)用場(chǎng)景,TCP能提供可靠的數(shù)據(jù)傳輸,UDP則有更高的傳輸效率,此處不再贅述TCP與UDP的區(qū)別,最終選擇哪種協(xié)議實(shí)現(xiàn),是一個(gè)見(jiàn)仁見(jiàn)智的問(wèn)題,需結(jié)合整體應(yīng)用場(chǎng)景、開(kāi)發(fā)代價(jià)、部署和運(yùn)營(yíng)成本等方面綜合考慮。
關(guān)于UDP與TCP協(xié)議的選擇,可以進(jìn)一步閱讀:
簡(jiǎn)述傳輸層協(xié)議TCP和UDP的區(qū)別
為什么QQ用的是UDP協(xié)議而不是TCP協(xié)議?
移動(dòng)端即時(shí)通訊協(xié)議選擇:UDP還是TCP?
快速理解TCP和UDP的差異
快速理解為什么說(shuō)UDP有時(shí)比TCP更有優(yōu)勢(shì)
我們的思路是:TCP為主,同時(shí)小流量探索QUIC的潛力。
百度iOS端長(zhǎng)連接SDK中現(xiàn)有兩套數(shù)據(jù)傳輸方案。
1)方案一:
在長(zhǎng)連接SDK建設(shè)初期,根據(jù)業(yè)內(nèi)成熟技術(shù)方案選型的調(diào)研結(jié)果,及開(kāi)發(fā)成本、維護(hù)便捷性的考慮,第一個(gè)方案是參考CocoaAsyncSocket框架改寫(xiě)的。
它是基于Socket原生開(kāi)發(fā),使用TCP協(xié)議,支持TLS/SSL安全傳輸,并且是線程安全的,該方案較為成熟,使用便捷,建連成功率較高。目前百度APP iOS端中90%的用戶流量都是走的該方案實(shí)現(xiàn)的長(zhǎng)連接邏輯。
2)方案二:
一般穩(wěn)定網(wǎng)絡(luò)傳輸都是通過(guò)TCP,但在網(wǎng)絡(luò)基建本身已經(jīng)越來(lái)越完善的情況下,TCP一些設(shè)計(jì)本身的問(wèn)題便暴露了出來(lái),加之TCP是在操作內(nèi)核和中間固件中實(shí)現(xiàn)的,因此對(duì)TCP進(jìn)行重大更改幾乎是很難的事情,類似建連過(guò)程握手耗時(shí)長(zhǎng)、隊(duì)頭阻塞等問(wèn)題沒(méi)有得到很好地解決,讓我們開(kāi)始考慮一些新的可能性。
于是,長(zhǎng)連接SDK后續(xù)引入了基于QUIC協(xié)議實(shí)現(xiàn)的第二套方案。
QUIC協(xié)議是建立在UDP之上,并且實(shí)現(xiàn)了可靠傳輸。
相比HTTP2+TCP+TLS協(xié)議,QUIC具有不少優(yōu)點(diǎn):
1)減少了TCP三次握手及TLS握手時(shí)間;
2)改進(jìn)了擁塞控制;
3)沒(méi)有隊(duì)頭阻塞的多路復(fù)用;
4)支持連接遷移。
百度iOS長(zhǎng)連接SDK目前通過(guò)NWConnection引入了QUIC協(xié)議的實(shí)現(xiàn)。QUIC的協(xié)議雖然比較先進(jìn),但這也意味著在工程實(shí)現(xiàn)方面有更多可優(yōu)化的空間,目前方案二還處于小流量實(shí)驗(yàn)階段,仍有很多優(yōu)化工作有待后續(xù)進(jìn)一步去落地。就當(dāng)前放量所得到的數(shù)據(jù)來(lái)看,在長(zhǎng)連接建連成功率及時(shí)延指標(biāo)上,QUIC實(shí)現(xiàn)方案都有較好的表現(xiàn)。
以下是關(guān)于QUIC的實(shí)踐資料:
技術(shù)掃盲:新一代基于UDP的低延時(shí)網(wǎng)絡(luò)傳輸層協(xié)議——QUIC詳解
讓互聯(lián)網(wǎng)更快:新一代QUIC協(xié)議在騰訊的技術(shù)實(shí)踐分享
7.3挑戰(zhàn)②:DNS解析優(yōu)化
這個(gè)問(wèn)題點(diǎn),主要原因是國(guó)內(nèi)移動(dòng)端網(wǎng)絡(luò)所面臨的DNS疑難雜癥。
國(guó)內(nèi)各ISP運(yùn)營(yíng)商的LocalDNS由于域名緩存、解析轉(zhuǎn)發(fā)、LocalDNS遞歸出口NAT的原因,容易引起DNS被劫持造成服務(wù)不可用、DNS調(diào)度不準(zhǔn)確導(dǎo)致性能退化等問(wèn)題。DNS解析的效率和準(zhǔn)確性,直接影響長(zhǎng)連接建連的質(zhì)量,進(jìn)而影響公司的業(yè)務(wù)。
我們的解決方案是在百度iOS端長(zhǎng)連接SDK中,采用當(dāng)前業(yè)界比較主流的解決方案:HTTPDNS來(lái)替代LocalDNS解析。
HTTPDNS是利用HTTP協(xié)議與DNS服務(wù)器進(jìn)行交互,繞開(kāi)了運(yùn)營(yíng)商的LocalDNS服務(wù),有效防止了域名劫持,提高域名解析效率。
關(guān)于DNS優(yōu)化的資料,可以繼續(xù)深入閱讀以下資料:
不為人知的網(wǎng)絡(luò)編程(九):理論聯(lián)系實(shí)際,全方位深入理解DNS
全面了解移動(dòng)端DNS域名劫持等雜癥:原理、根源、HttpDNS解決方案等
美圖App的移動(dòng)端DNS優(yōu)化實(shí)踐:HTTPS請(qǐng)求耗時(shí)減小近半
移動(dòng)端網(wǎng)絡(luò)優(yōu)化之HTTP請(qǐng)求的DNS優(yōu)化
百度APP移動(dòng)端網(wǎng)絡(luò)深度優(yōu)化實(shí)踐分享(一):DNS優(yōu)化篇
7.4完整解決方案(百度iOS端長(zhǎng)連接建連整體流程)
在百度APP中,統(tǒng)一維護(hù)了一系列系統(tǒng)事件和生命周期供各個(gè)組件監(jiān)聽(tīng)。iOS長(zhǎng)連接SDK根據(jù)百度APP的業(yè)務(wù)特性,選擇在環(huán)境搭建完成事件后觸發(fā)長(zhǎng)連接建連,即等待APP啟動(dòng)必要數(shù)據(jù)比如首頁(yè)資源等加載完成后,開(kāi)始觸發(fā)長(zhǎng)連接建連。

上圖展示了長(zhǎng)連接SDK建連的四個(gè)過(guò)程(下面將詳細(xì)說(shuō)明之)。
1)獲取Token:
*?獲取Token的意義:狹義上Token指的是長(zhǎng)連接訪問(wèn)控制模塊返回的access-token,后續(xù)隨長(zhǎng)連接登錄請(qǐng)求上行到長(zhǎng)連接接入層,由接入層向長(zhǎng)連接訪問(wèn)控制模塊進(jìn)行鑒權(quán)用。廣義上隨此次Token請(qǐng)求下發(fā)的,還有傳輸協(xié)議及訪問(wèn)點(diǎn)等數(shù)據(jù),包括但不限于:長(zhǎng)連接協(xié)議使用QUIC還是TCP,是否優(yōu)先ipv6,連接域名和端口,日志打點(diǎn)小流量開(kāi)關(guān)等。
*?獲取Token的機(jī)制:獲取Token優(yōu)先走本地緩存,當(dāng)本地緩存無(wú)有效數(shù)據(jù)時(shí),才發(fā)出網(wǎng)絡(luò)請(qǐng)求,該請(qǐng)求是基于NSURLSession實(shí)現(xiàn)的短連接請(qǐng)求;Token在服務(wù)端和客戶端均有緩存,存在過(guò)期時(shí)間,若Token過(guò)期,會(huì)在下圖中階段四通過(guò)長(zhǎng)連接登錄請(qǐng)求失敗體現(xiàn),這時(shí)會(huì)清空本地Token緩存并觸發(fā)重新建連。
2)DNS域名解析:如前所述,長(zhǎng)連接SDK中使用HTTPDNS替代LocalDNS來(lái)防止DNS劫持、提高解析效率。同時(shí)在iOS Release環(huán)境下,為提高DNS解析效率,本地建立了緩存機(jī)制,HTTPDNS解析結(jié)果返回后會(huì)更新本地緩存,下次建連過(guò)程優(yōu)先取緩存,緩存不合法才走網(wǎng)絡(luò)請(qǐng)求。
3)建立Socket連接:Socket建連過(guò)程涉及到傳輸協(xié)議的選擇,根據(jù)前面介紹,iOS長(zhǎng)連接SDK目前是通過(guò)小流量實(shí)驗(yàn)的方式,10%的用戶走QUIC建連,90%的用戶走TCP建連。
4)長(zhǎng)連接登錄請(qǐng)求:攜帶Token中獲取的access-token上行請(qǐng)求完成鑒權(quán),長(zhǎng)連接登錄請(qǐng)求返回成功意味著整個(gè)建連過(guò)程完成,業(yè)務(wù)層可開(kāi)始正常使用長(zhǎng)連接進(jìn)行通訊,若登錄返回報(bào)錯(cuò),則會(huì)觸發(fā)重連。
順利完成這四個(gè)階段后,長(zhǎng)連接會(huì)在該鏈路上持續(xù)發(fā)送心跳包進(jìn)行連接保活,在異常斷連或壓后臺(tái)等觸發(fā)的主動(dòng)斷連之前,一直保持連接在線狀態(tài),為各個(gè)業(yè)務(wù)的數(shù)據(jù)傳輸提供通路。
8、核心技術(shù)邏輯2:連接的維護(hù)
8.1維護(hù)長(zhǎng)連接的意義
上節(jié)介紹了長(zhǎng)連接連接建立的全過(guò)程。socket長(zhǎng)連接建連成功后,實(shí)際已處于可用狀態(tài),即各業(yè)務(wù)基于長(zhǎng)連接的通信已經(jīng)可以正常進(jìn)行。
但在此之后,保持長(zhǎng)連接的可用性也是非常重要的。如果長(zhǎng)連接無(wú)法很好地保持,在連接已經(jīng)失效的情況下服務(wù)端繼續(xù)推送下行通知而端卻收不到,造成資源的浪費(fèi),同時(shí)無(wú)法及時(shí)重新建連,對(duì)業(yè)務(wù)造成損失。
8.2維護(hù)長(zhǎng)連接的解決方案
針對(duì)可能導(dǎo)致長(zhǎng)連接斷開(kāi)的幾種主要原因,長(zhǎng)連接SDK建立了對(duì)應(yīng)的機(jī)制來(lái)保證連接的穩(wěn)定性,可總結(jié)為兩點(diǎn):心跳?;詈蛿嗑€重連。

1)解決方案①:心跳保活
心跳?;畹亩x:實(shí)現(xiàn)長(zhǎng)連接保活的方式通常是采用應(yīng)用層心跳,通過(guò)心跳包的超時(shí)或報(bào)錯(cuò)等來(lái)執(zhí)行重連操作。心跳一般是指某端(通常是客戶端)每隔一定時(shí)間向另一端(通常是服務(wù)端)發(fā)送自定義指令,以判斷雙方是否存活,因其按照一定間隔發(fā)送,類似于心跳,故被稱為心跳保活。
百度iOS端長(zhǎng)連接SDK心跳?;顧C(jī)制:長(zhǎng)連接登陸請(qǐng)求成功后,解析返回?cái)?shù)據(jù),若服務(wù)端下發(fā)了心跳包的間隔時(shí)間,則以服務(wù)端下發(fā)的時(shí)間間隔持續(xù)發(fā)送心跳包進(jìn)行連接?;睿魶](méi)有下發(fā)心跳包間隔時(shí)間,客戶端會(huì)默認(rèn)60s間隔時(shí)間來(lái)觸發(fā)心跳包的發(fā)送。
具體心跳?;钸^(guò)程見(jiàn)下圖:

2)解決方案②:斷線重連
斷線重連原理:在長(zhǎng)連接可能被斷開(kāi)的場(chǎng)景(壓后臺(tái)重進(jìn)APP、網(wǎng)絡(luò)狀態(tài)變更等),檢測(cè)長(zhǎng)連接的可用狀態(tài),監(jiān)測(cè)到連接不可用時(shí),及時(shí)觸發(fā)重連機(jī)制。
百度iOS端長(zhǎng)連接SDK斷線重連機(jī)制:具體觸發(fā)斷線重連的時(shí)機(jī)見(jiàn)下圖,iOS長(zhǎng)連接SDK內(nèi)部維護(hù)有串行隊(duì)列和統(tǒng)一的長(zhǎng)連接狀態(tài)監(jiān)測(cè)記錄,不會(huì)導(dǎo)致重復(fù)建連的發(fā)生。
具體斷線重連邏輯見(jiàn)下圖:

心跳?;詈蛿嗑€重連相關(guān)資料,可以繼續(xù)深入閱讀:
為何基于TCP協(xié)議的移動(dòng)端IM仍然需要心跳?;顧C(jī)制?
一文讀懂即時(shí)通訊應(yīng)用中的網(wǎng)絡(luò)心跳包機(jī)制:作用、原理、實(shí)現(xiàn)思路等
微信團(tuán)隊(duì)原創(chuàng)分享:Android版微信后臺(tái)?;顚?shí)戰(zhàn)分享(網(wǎng)絡(luò)保活篇)
移動(dòng)端IM實(shí)踐:實(shí)現(xiàn)Android版微信的智能心跳機(jī)制
融云技術(shù)分享:融云安卓端IM產(chǎn)品的網(wǎng)絡(luò)鏈路?;罴夹g(shù)實(shí)踐
Web端即時(shí)通訊實(shí)踐干貨:如何讓你的WebSocket斷網(wǎng)重連更快速?
跟著源碼學(xué)IM(一):手把手教你用Netty實(shí)現(xiàn)心跳機(jī)制、斷線重連機(jī)制
跟著源碼學(xué)IM(五):正確理解IM長(zhǎng)連接、心跳及重連機(jī)制,并動(dòng)手實(shí)現(xiàn)
萬(wàn)字長(zhǎng)文:手把手教你實(shí)現(xiàn)一套高效的IM長(zhǎng)連接自適應(yīng)心跳?;顧C(jī)制
9、長(zhǎng)連接在百度APP中的業(yè)務(wù)落地
長(zhǎng)連接是客戶端到服務(wù)端的一種全雙工連接,建連完成后,可以為業(yè)務(wù)方提供請(qǐng)求轉(zhuǎn)發(fā)、服務(wù)端主動(dòng)推送等服務(wù)。
在百度APP中,包括在線健康診療、高考志愿填報(bào)咨詢、情感心理輔導(dǎo)等一系列實(shí)時(shí)咨詢服務(wù),發(fā)送直播彈幕、加入某大V粉絲群聊天、私信好友等多種用戶實(shí)時(shí)溝通場(chǎng)景的落地,以及實(shí)現(xiàn)用戶在線情況下云端可及時(shí)主動(dòng)下發(fā)配置控制端的基礎(chǔ)能力建設(shè),都離不開(kāi)長(zhǎng)連接的支持。長(zhǎng)連接為各個(gè)業(yè)務(wù)與自己服務(wù)端的數(shù)據(jù)交互提供了穩(wěn)定便捷的方式和渠道。
下圖為百度APP中長(zhǎng)連接與落地業(yè)務(wù)的結(jié)構(gòu)示意圖:

完整的長(zhǎng)連接模塊包括了客戶端的長(zhǎng)連接SDK和服務(wù)端的長(zhǎng)連接接入層兩個(gè)部分,作為各個(gè)業(yè)務(wù)與自己服務(wù)端數(shù)據(jù)交流的中間渠道,處理了包括連接建立與保活、實(shí)現(xiàn)各業(yè)務(wù)客戶端與自己服務(wù)端的數(shù)據(jù)雙向互發(fā)等邏輯。
下面將重點(diǎn)關(guān)注長(zhǎng)連接在IMSDK實(shí)時(shí)聊天通訊場(chǎng)景中的實(shí)踐。
10、長(zhǎng)連接在IM即時(shí)通訊場(chǎng)景中的落地實(shí)踐
10.1背景
IMSDK,即百度消息中臺(tái)(見(jiàn)《揭秘百度IM消息中臺(tái)的全量用戶消息推送技術(shù)改造實(shí)踐》)為百度APP及百度系其他產(chǎn)品打造的具備應(yīng)用內(nèi)即時(shí)通訊能力的客戶端SDK,包括多種用戶溝通場(chǎng)景:私聊、群聊、聊天室、直播彈幕等,并幫助業(yè)務(wù)推送消息通知觸達(dá)用戶,建立B端和C端的溝通渠道。
目前主功能諸如拉取會(huì)話列表、拉取消息、發(fā)送消息、消息已讀等均為長(zhǎng)連接實(shí)現(xiàn)。
本小節(jié)將通過(guò)介紹用戶發(fā)送消息、用戶收到新消息通知這兩個(gè)IM及時(shí)通訊中的常見(jiàn)場(chǎng)景,展示長(zhǎng)連接提供的數(shù)據(jù)轉(zhuǎn)發(fā)和服務(wù)器主動(dòng)推送能力是如何在業(yè)務(wù)場(chǎng)景落地的。
10.2實(shí)踐1:IM聊天場(chǎng)景下用戶發(fā)送消息
1)實(shí)踐場(chǎng)景:
IM聊天場(chǎng)景下,用戶在聊天框向自己好友發(fā)送一條消息,消息如果發(fā)送失敗了,應(yīng)用通常會(huì)在本條消息氣泡旁展示一個(gè)紅嘆號(hào)(或類似意義的圖標(biāo)),這個(gè)應(yīng)用場(chǎng)景對(duì)于互聯(lián)網(wǎng)用戶應(yīng)該都非常熟悉(如下圖所示)。

從技術(shù)角度看,本質(zhì)上是業(yè)務(wù)客戶端向自己的服務(wù)器上行一個(gè)請(qǐng)求,服務(wù)器再將請(qǐng)求結(jié)果返回給客戶端。這是一個(gè)典型的需要頻繁點(diǎn)到點(diǎn)通信的場(chǎng)景,非常適合基于長(zhǎng)連接來(lái)實(shí)現(xiàn)。
長(zhǎng)連接SDK對(duì)外提供了封裝好的長(zhǎng)連接請(qǐng)求類,外部業(yè)務(wù)方諸如IMSDK在上行長(zhǎng)連接請(qǐng)求時(shí)通過(guò)創(chuàng)建該類的實(shí)例,將上行所需參數(shù)和數(shù)據(jù)賦值給請(qǐng)求實(shí)例,并設(shè)置回調(diào)閉包用于接收和處理請(qǐng)求回執(zhí)數(shù)據(jù)和結(jié)果,最后將請(qǐng)求發(fā)出。業(yè)務(wù)不需要考慮數(shù)據(jù)傳輸及轉(zhuǎn)發(fā)等邏輯,長(zhǎng)連接會(huì)充當(dāng)業(yè)務(wù)客戶端和服務(wù)器之間的通路,黑盒處理這個(gè)過(guò)程。
2)技術(shù)難點(diǎn):
對(duì)于長(zhǎng)連接SDK而言,在這條通路上最重要也是比較復(fù)雜的邏輯點(diǎn)在于,各個(gè)業(yè)務(wù)方的上行請(qǐng)求和下行通知都是并發(fā)進(jìn)行的,長(zhǎng)連接SDK如何有序地管理數(shù)據(jù)流向。
上行請(qǐng)求即寫(xiě)流,接收下行數(shù)據(jù)即讀流,下面就讀寫(xiě)流的管理,與請(qǐng)求同回執(zhí)數(shù)據(jù)的匹配問(wèn)題的解決方案作簡(jiǎn)要的介紹。
3)技術(shù)實(shí)現(xiàn)
長(zhǎng)連接SDK內(nèi)就讀寫(xiě)數(shù)據(jù)維護(hù)有兩個(gè)隊(duì)列:讀隊(duì)列和寫(xiě)隊(duì)列,以及維護(hù)了一個(gè)緩存池用作請(qǐng)求實(shí)例和請(qǐng)求回執(zhí)數(shù)據(jù)的匹配。
業(yè)務(wù)方上行一個(gè)長(zhǎng)連接請(qǐng)求,實(shí)際上是將請(qǐng)求任務(wù)添加到寫(xiě)隊(duì)列中,如果此時(shí)處于可寫(xiě)流狀態(tài),還會(huì)觸發(fā)寫(xiě)流。當(dāng)socket建連成功以后,會(huì)取出寫(xiě)隊(duì)列隊(duì)頭的任務(wù),開(kāi)始寫(xiě)流,寫(xiě)流完畢會(huì)檢查寫(xiě)隊(duì)列是否為空,不為空繼續(xù)取隊(duì)頭任務(wù)執(zhí)行,直至寫(xiě)隊(duì)列為空為止。
同時(shí)socket建連成功還會(huì)添加一次讀任務(wù)到讀隊(duì)列中,并檢查如果此時(shí)處于可讀狀態(tài),便取出隊(duì)頭第一個(gè)讀任務(wù),開(kāi)始讀流,讀流成功后會(huì)繼續(xù)添加一個(gè)讀任務(wù)到讀隊(duì)列,循環(huán)讀流操作。
讀流得到的服務(wù)端下行返回?cái)?shù)據(jù),通過(guò)serviceId(業(yè)務(wù)編號(hào))+ methodId(長(zhǎng)連接請(qǐng)求方法編號(hào))+ 請(qǐng)求發(fā)起的時(shí)間戳組成唯一鍵值,去緩存區(qū)匹配到下行返回?cái)?shù)據(jù)對(duì)應(yīng)的請(qǐng)求體,通過(guò)回調(diào)的方式,將請(qǐng)求結(jié)果返回到調(diào)用方。該請(qǐng)求一旦被回調(diào)過(guò)一次,其實(shí)例將從緩存區(qū)被刪除,及時(shí)釋放緩存區(qū)內(nèi)存,并且保證一次請(qǐng)求不會(huì)發(fā)生多次回調(diào)的情況。

10.3實(shí)踐2:IM聊天場(chǎng)景下用戶收到新消息通知
1)實(shí)踐場(chǎng)景:
IM聊天場(chǎng)景下,用戶是如何收到別的用戶發(fā)送給他的新消息通知的呢?
其實(shí)是依靠服務(wù)器的下行通知到客戶端。
長(zhǎng)連接不僅提供為業(yè)務(wù)客戶端轉(zhuǎn)發(fā)上行請(qǐng)求的能力,還提供了服務(wù)端主動(dòng)推送的服務(wù)。
比如在IM業(yè)務(wù)中,依靠IM服務(wù)器下行新消息通知,來(lái)完成消息的實(shí)時(shí)接收和拉取。這些通知又是如何到達(dá)IMSDK的呢?其實(shí)它與上一小節(jié)IMSDK上行長(zhǎng)連接請(qǐng)求的過(guò)程類似。
2)技術(shù)實(shí)現(xiàn):
在IMSDK的長(zhǎng)連接管理類初始化階段,會(huì)對(duì)需要接收的下行通知方法進(jìn)行注冊(cè),這里的注冊(cè)實(shí)際上指的就是上行多個(gè)長(zhǎng)連接請(qǐng)求,每個(gè)請(qǐng)求有對(duì)應(yīng)的serviceID(業(yè)務(wù)編號(hào))和methodID(需要注冊(cè)的通知方法號(hào)碼)。
跟上一小節(jié)長(zhǎng)連接請(qǐng)求不同的點(diǎn)在于,這些請(qǐng)求在收到回執(zhí)數(shù)據(jù)后不會(huì)從長(zhǎng)連接SDK請(qǐng)求緩存區(qū)里移除,而是會(huì)長(zhǎng)期存在,只要讀流時(shí)讀到了對(duì)應(yīng)methodID的數(shù)據(jù),就能在請(qǐng)求緩存區(qū)找到對(duì)應(yīng)請(qǐng)求,將下行數(shù)據(jù)傳到IMSDK了。
這樣一來(lái),只要長(zhǎng)連接在線,業(yè)務(wù)方就能實(shí)時(shí)接收到其服務(wù)器下行的通知消息了。
11、本文小結(jié)
長(zhǎng)連接服務(wù)的核心大致可分為:建連過(guò)程、連接維持過(guò)程以及數(shù)據(jù)傳輸過(guò)程。
本文給出了搭建長(zhǎng)連接服務(wù)過(guò)程中面臨的一些挑戰(zhàn)和解決方案,并結(jié)合長(zhǎng)連接功能在百度APP的IM即時(shí)通訊場(chǎng)景下的實(shí)踐,簡(jiǎn)要介紹了百度iOS端長(zhǎng)連接SDK的整體架構(gòu)。
在移動(dòng)端,長(zhǎng)連接技術(shù)的應(yīng)用前景非常廣闊。隨著5G和6G等高速移動(dòng)網(wǎng)絡(luò)的發(fā)展,將使得移動(dòng)應(yīng)用程序能夠更加高效地使用長(zhǎng)連接技術(shù),從而實(shí)現(xiàn)更加實(shí)時(shí)和高效的數(shù)據(jù)交換。這也為對(duì)實(shí)時(shí)數(shù)據(jù)交換有強(qiáng)需求的應(yīng)用場(chǎng)景提供了更廣闊的想象空間,諸如物聯(lián)網(wǎng)、智能家居、虛擬現(xiàn)實(shí)和增強(qiáng)現(xiàn)實(shí)等技術(shù),長(zhǎng)連接都將在其中發(fā)揮更加重要的作用。
12、參考資料
[1]?一泡尿的時(shí)間,快速讀懂QUIC協(xié)議
[2]?網(wǎng)絡(luò)編程懶人入門(mén)(八):手把手教你寫(xiě)基于TCP的Socket長(zhǎng)連接
[3]?網(wǎng)絡(luò)編程懶人入門(mén)(十四):到底什么是Socket?一文即懂!
[4]?腦殘式網(wǎng)絡(luò)編程入門(mén)(二):我們?cè)谧x寫(xiě)Socket時(shí),究竟在讀寫(xiě)什么?
[5]?聊聊iOS中網(wǎng)絡(luò)編程長(zhǎng)連接的那些事
[6]?全面了解移動(dòng)端DNS域名劫持等雜癥:原理、根源、HttpDNS解決方案等
[7]?美圖App的移動(dòng)端DNS優(yōu)化實(shí)踐:HTTPS請(qǐng)求耗時(shí)減小近半
[8]?百度APP移動(dòng)端網(wǎng)絡(luò)深度優(yōu)化實(shí)踐分享(一):DNS優(yōu)化篇
[9]?為何基于TCP協(xié)議的移動(dòng)端IM仍然需要心跳?;顧C(jī)制?
[10]?一文讀懂即時(shí)通訊應(yīng)用中的網(wǎng)絡(luò)心跳包機(jī)制:作用、原理、實(shí)現(xiàn)思路等
[11]?微信團(tuán)隊(duì)原創(chuàng)分享:Android版微信后臺(tái)?;顚?shí)戰(zhàn)分享(網(wǎng)絡(luò)保活篇)
[12]?Web端即時(shí)通訊實(shí)踐干貨:如何讓你的WebSocket斷網(wǎng)重連更快速?
[13]?跟著源碼學(xué)IM(五):正確理解IM長(zhǎng)連接、心跳及重連機(jī)制,并動(dòng)手實(shí)現(xiàn)
[14]?萬(wàn)字長(zhǎng)文:手把手教你實(shí)現(xiàn)一套高效的IM長(zhǎng)連接自適應(yīng)心跳?;顧C(jī)制
[15]?揭秘百度IM消息中臺(tái)的全量用戶消息推送技術(shù)改造實(shí)踐
(本文已同步發(fā)布于:http://www.52im.net/thread-4359-1-1.html)