引言
即使在通信如此發達的今天,IM 也依然是諸多場景下很是重要的基礎能力。所以作爲 一名 Android 開發,不可避免的會遇到一些IM 相關的需求或問題。本文以一個Android開發的角度來說述IM 開發相關的基礎知識。
瞭解
網易雲信,來自網易核心架構的通訊與視頻雲服務。
IM開發須要面對的問題
-
網絡問題,如何高效快速的傳輸數據?
-
協議問題,消息如何封裝?
-
及時性問題,如何進行進程保活?
網絡問題
TCP 的三次握手創建鏈接是一個很是耗時的過程。在 IM 場景下,數據的傳輸將會很是的頻繁,若是每次傳輸都創建一個 TCP 鏈接,那麼這個效率是不能接受的,而且頻繁的創建鏈接可能會發生socket錯誤,因此咱們須要 「複用」TCP鏈接,也就是平時所說的TCP長鏈接。
短鏈接在創建後,當數據傳輸完畢時會當即關閉,下次須要傳輸數據時須要從新創建鏈接,在平常的業務場景很是常見,好比經過 http/https 請求獲取Server 數據。而長鏈接在傳輸完數據後並不會關閉,這樣下次須要傳輸數據時就能夠直接使用已經創建好的鏈接,這中間省去了鏈接創建的時間。可是創建一個 TCP 長鏈接卻並非「創建後不關閉」那麼簡單,由於 TCP 長鏈接會「被動」關閉。
IPv4的容量是有限的,隨着接入Internet的計算機數量的不斷猛增,IP地址資源也就越發顯得捉襟見肘,因而也就產生了 NAT技術。簡單來講,NAT就是在局域網內部網絡中使用內部地址,而當內部節點要與外部網絡進行通信時,就在網關(能夠理解爲出口,打個比方就像院子的門同樣)處,將內部地址替換成公用地址,從而在外部公網(Internet)上正常使用,NAT可使多臺計算機共享Internet鏈接,這一功能很好地解決了公共 IP地址緊缺的問題。經過這種方法,能夠只申請一個合法IP地址,就把整個局域網中的計算機接入Internet中。
而咱們就處於運營商(移動/聯通/電信。。。)的局域網內。當咱們接入運營商的網絡後,會分配到一個運營商的內部 IP地址,因而咱們就可使用這個IP地址創建鏈接向外傳輸數據了。可是當這個IP閒置了一段時間(NAT超時時間)後,運營商爲了節約資源,會把分配給咱們IP回收掉。此時若是咱們還繼續使用以前那個未關閉的鏈接去傳輸數據,那麼毫無疑問會失敗的。下面是一些運營商的 NAT超時時間。
網絡NAT超時時間中國移動3G/2G5 min中國聯通2G5 min中國電信3G大於 28 min
要想長鏈接一直有效,那麼閒置時間就不能太長,因此在閒置時咱們須要向外(Server)傳輸一些數據包,這也就是常說的「心跳包」,用於告訴運營商這個 IP 還在被使用,告訴Server 客戶端還在線。
這裏講一下固定心跳,動態心跳能夠參考
微信心跳 。固定心跳其實就是間隔固定時間發送一個心跳包。
心跳間隔 X 的值須要參考運營商的 NAT 超時時間肯定,不能大於最小的 NAT超時時間,也不能過小,要不Server 的負擔很是重。通常取一個比較接近最小的NAT超時時間,好比4分鐘。
協議問題
協議決定是消息以什麼樣的形式傳輸,即發送時若是對消息進行封裝,接收時如何解析。好比能夠將消息體以 XML 的形式進行處理,這也就是 XMPP 協議,參考下面一個消息示意:
<message>
<from>隔壁老王</from>
<to>老李</to>
<context>你兒子長的比你帥多了。</context>
<type>text</type>
</message>
<message>
<from>老李</from>
<to>隔壁老王</to>
<context>嘿嘿,謝謝誇獎!</context>
<type>text</type>
</message>複製代碼
從上面的消息示意,咱們能夠發現一條消息的內容能夠拆分紅不少屬性,而協議就是把這些屬性組合起來。
以 XML 的形式傳輸消息,最大的一個問題,就是冗餘數據太多了,特別是當消息的屬性比較多時。
其實不管消息如何封裝,最終傳輸的確定是二進制流,那麼徹底能夠直接用二進制的形式對消息進行封裝,這也就是二進制協議。下面是一個簡單二進制協議的實現示意。
一條消息由from + to + context + type這幾個屬性組成,那麼咱們徹底能夠按順序存儲在二進制中,因爲內容長度不肯定,因此每一個屬性的開頭咱們可使用固定字節數來記錄這個屬性的內容長度。固然,這裏只是展現了一個二進制協議的例子,實際的消息會比這複雜多了,可是核心思路就是這麼簡單,最終無非是設計與實現形式上的差距。
及時性問題
IM的做爲即時通信,若是沒法保證消息及時觸達,那麼意義就大打折扣。要保證消息及時觸達,最關鍵要作到如下兩點:
1. App 進程要儘可能存活,也就是進程保活 ;
進程保活實際上是屬於 Android 平臺的一個話題,相信你們平常開發也遇到過,細節就不在這長篇大論了,簡單的說下幾個原則:
1. 優化內存,減少內存的佔用,會大大的減少被 kill 的機率;
2. 多進程,將 UI 進程與 IM 進程獨立出來,這樣 IM 的進程負擔就會小不少;
嚴格意義上來講進程喚醒是屬於進程保活的一個分支,這裏單獨列出來,是由於進程喚醒關注的是進程掛掉以後的動做。對於進程喚醒,這裏也只列些原則,詳細的能夠去查閱相關資料。
2. Alarm定時任務,定時去檢查進程是否存活。
3. JobScheduler定時任務,定時去檢查進程是否存活( >5.0 )
網易雲信(NeteaseYunXin)是集網易18年IM以及音視頻技術打造的PaaS服務產品,來自網易核心技術架構的通訊與視頻雲服務,穩定易用且功能全面,致力於提供全球領先的技術能力和場景化解決方案。開發者經過集成客戶端SDK和雲端OPEN API,便可快速實現包含IM、音視頻通話、直播、點播、互動白板、短信等功能。