Android開發需要了解的 IM 知識

網易雲信發表於2018-12-21

引言

即便在通訊如此發達的今天,IM 也依然是諸多場景下非常重要的基礎能力。因此做為 一名 Android 開發,不可避免的會遇到一些IM 相關的需求或問題。本文以一個Android開發的角度來講述IM 開發相關的基礎知識。

想要閱讀更多技術乾貨、行業洞察,歡迎關注網易雲信部落格
瞭解網易雲信,來自網易核心架構的通訊與視訊雲服務。

IM開發需要面對的問題

  1. 網路問題,如何高效快速的傳輸資料?
  2. 協議問題,訊息如何封裝?
  3. 及時性問題,如何進行程式保活?

網路問題

  TCP 的三次握手建立連線是一個非常耗時的過程。在 IM 場景下,資料的傳輸將會非常的頻繁,如果每次傳輸都建立一個 TCP 連線,那麼這個效率是不能接受的,並且頻繁的建立連線可能會發生socket錯誤,所以我們需要 “複用”TCP連線,也就是平時所說的TCP長連線。
TCP 長連線
短連線在建立後,當資料傳輸完畢時會立即關閉,下次需要傳輸資料時需要重新建立連線,在日常的業務場景非常常見,比如通過 http/https 請求獲取Server 資料。而長連線在傳輸完資料後並不會關閉,這樣下次需要傳輸資料時就可以直接使用已經建立好的連線,這中間省去了連線建立的時間。但是建立一個 TCP 長連線卻並不是“建立後不關閉”那麼簡單,因為 TCP 長連線會“被動”關閉。
網路地址轉換 (NAT)
   IPv4的容量是有限的,隨著接入Internet的計算機數量的不斷猛增,IP地址資源也就愈加顯得捉襟見肘,於是也就產生了 NAT技術。簡單來說,NAT就是在區域網內部網路中使用內部地址,而當內部節點要與外部網路進行通訊時,就在閘道器(可以理解為出口,打個比方就像院子的門一樣)處,將內部地址替換成公用地址,從而在外部公網(Internet)上正常使用,NAT可以使多臺計算機共享Internet連線,這一功能很好地解決了公共 IP地址緊缺的問題。通過這種方法,可以只申請一個合法IP地址,就把整個區域網中的計算機接入Internet中。
Android開發需要了解的 IM 知識
  而我們就處於運營商(移動/聯通/電信。。。)的區域網內。當我們接入運營商的網路後,會分配到一個運營商的內部 IP地址,於是我們就可以使用這個IP地址建立連線向外傳輸資料了。但是當這個IP閒置了一段時間(NAT超時時間)後,運營商為了節約資源,會把分配給我們IP回收掉。此時如果我們還繼續使用之前那個未關閉的連線去傳輸資料,那麼毫無疑問會失敗的。下面是一些運營商的 NAT超時時間。
網路NAT超時時間中國移動3G/2G5 min中國聯通2G5 min中國電信3G大於 28 min
   要想長連線一直有效,那麼閒置時間就不能太長,所以在閒置時我們需要向外(Server)傳輸一些資料包,這也就是常說的“心跳包”,用於告訴運營商這個 IP 還在被使用,告訴Server 客戶端還線上。
心跳策略
  心跳策略一般分為兩種:
    1. 固定心跳
    2. 動態心跳
這裡講一下固定心跳,動態心跳可以參考 微信心跳 。固定心跳其實就是間隔固定時間傳送一個心跳包。
Android開發需要了解的 IM 知識

心跳間隔 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 的形式傳輸訊息,最大的一個問題,就是冗餘資料太多了,特別是當訊息的屬性比較多時。
  那麼有沒什麼格式能儘可能有減小冗餘資料?
  其實無論訊息如何封裝,最終傳輸的肯定是二進位制流,那麼完全可以直接用二進位制的形式對訊息進行封裝,這也就是二進位制協議。下面是一個簡單二進位制協議的實現示意。
Android開發需要了解的 IM 知識
  一條訊息由from + to + context + type這幾個屬性組成,那麼我們完全可以按順序儲存在二進位制中,由於內容長度不確定,所以每個屬性的開頭我們可以使用固定位元組數來記錄這個屬性的內容長度。當然,這裡只是展示了一個二進位制協議的例子,實際的訊息會比這複雜多了,但是核心思路就是這麼簡單,最終無非是設計與實現形式上的差距。

及時性問題

  IM的作為即時通訊,如果無法保證訊息及時觸達,那麼意義就大打折扣。要保證訊息及時觸達,最關鍵要做到以下兩點:
   1. App 程式要儘量存活,也就是程式保活 ;
   2. 在 App程式掛掉後,能夠喚醒起來;
程式保活
  程式保活其實是屬於 Android 平臺的一個話題,相信大家日常開發也遇到過,細節就不在這長篇大論了,簡單的說下幾個原則:
   1. 優化記憶體,減小記憶體的佔用,會大大的減小被 kill 的機率;
   2. 多程式,將 UI 程式與 IM 程式獨立出來,這樣 IM 的程式負擔就會小很多;
程式喚醒
  嚴格意義上來說程式喚醒是屬於程式保活的一個分支,這裡單獨列出來,是因為程式喚醒關注的是程式掛掉之後的動作。對於程式喚醒,這裡也只列些原則,詳細的可以去查閱相關資料。
   1. 靜態註冊監聽廣播(<7.0)
   2. Alarm定時任務,定時去檢查程式是否存活。
   3. JobScheduler定時任務,定時去檢查程式是否存活( >5.0 )
   4. 接入廠商推送
網易雲信(NeteaseYunXin)是集網易18年IM以及音視訊技術打造的PaaS服務產品,來自網易核心技術架構的通訊與視訊雲服務,穩定易用且功能全面,致力於提供全球領先的技術能力和場景化解決方案。開發者通過整合客戶端SDK和雲端OPEN API,即可快速實現包含IM、音視訊通話、直播、點播、互動白板、簡訊等功能。


相關文章