Android平台上關於IM的實踐總結

來源:互聯網
上載者:User

標籤:android平台   socket   im   xmpp      

前言

IM通訊在互連網發展到現在已經是碼農的世界裡人盡皆知的技術,特別在當下移動互連網迅猛發展的時代這種技術的開發也更加火熱,其中老牌的代表作就有QQ和MSN,和最近新崛起的,默默,易信,來往等眼花繚亂的各種應用都把IM技術應用其中。我是Android開發人員,寫這篇文章主要原因也是因為我自己從事開發以來主要做過的幾款APP都是包含著IM通訊,在不斷的摸爬滾打的解決問題的過程中,積累了一些經驗記錄便將其記錄到部落格中作為自己一個階段性的總結,也可以分享其他需要的開發人員,作為一種參考實踐的方案,當然,我也並非神馬大神層級的人物,如果部落格中存在錯誤或者讀者看完後覺得有疑問,歡迎在文章下方留下你的建議或問題作為評論。

從socket到XMPP協議一個簡單完成的IM通訊流程如同下面的模型裡面1-2-3-4的步驟所示,兩個行動裝置之間的收發訊息都需要伺服器進行中轉並做訊息的轉寄。

整個IM流程中,伺服器接收訊息發送方的請求,並檢查接收方當前是否線上,如果線上的話則直接向接收方發送訊息,如果不線上則作為離線訊息儲存到資料庫中,等待接收方上線的時候再將訊息進行發送。
IM作為一門網路通訊的技術,必然涉及到通訊協定的問題,而在Android平台上做IM開發,目前我所涉及到的協議有socket和XMPP兩種類型,當然,這兩者並不是一種並列的關係,從嚴格意義上來說socket是Java所有網路實現通訊的基石,在Java上所有任何網路通訊協定通訊,最終都要依賴與socket來實現,在Android平台上使用XMPP協議通訊,其最終底層同樣還是依賴於socket實現,最典型的參考例子就是smack了,估計絕大多數小企業在做IM開發的時候,都會使用已經把XMPP協議封裝好smack,以此節省開發時間,smack本身就是用Java語言開發,並採用了mina作為核心實現的架構(mina本身就是一個Java的NIO通訊架構,但是很久不更新了,原先mina的作者寫了一個新的NIO通訊架構叫做netty,應該是做為mina的替代者)。作為socket和XMPP協議實現IM通訊其主要的優缺點如下:


因此,在實際的IM開發中,到底是選用XMPP協議和使用socket來實現,可以根據開發應用情境和他們的優劣來決定,當然,也不僅僅局限於IM開發,伺服器給用戶端做訊息推送也可以作為參考。

長串連和資料丟包IM開發中除了基本的訊息收發,以及協議使用方式的選擇外,還需要解決所有IM通訊技術所面臨的兩個共性問題。
其一,保持用戶端和伺服器間的長串連。這是由於業務情境所需要, IM通訊實現的基礎是需要時時刻刻保持用戶端在伺服器上的線上狀態,這樣才能保證發送方的訊息能夠及時到接收方,特別是的設計概念出來後,IM類型的用戶端已經沒有線上和離線狀態的區別了,這是和QQ最大的區別 ,在這種情況下對用戶端即時線上的要求就變得更高。那麼作為用戶端如何即時保持線上狀態呢?由於Java網路通訊的最底層都要依賴於socket來實現,而socket又分為UDP和TCP兩種類型,從理論上來講,我們使用TCP類型的socket來做實現通訊即可保證長串連的實現,不過這僅僅是理論上而已,為什麼單靠TCP不行咧,這跟我們真是的網路環境和作業系統都有一定的關係,預知為毛,請接著往下看。
首先,在上一面那種簡單的IM通訊圖中,僅僅列出了IM通訊的伺服器和用戶端,但是在實際的網路環境是非常複雜的(如所示,黃色的閃電圖形代表一個串連),我們發送的訊息報文是需要經過很多不同的電訊廠商線路,在各個交換器和路由器間穿梭才能最終到達接收方的裝置上,是一個簡單的網路訊息傳遞圖,黃色的閃電線連起來就是TCP所保持的長串連,理論上這個連結是一直保持通暢的,所以用戶端只需建立串連後就可以撒手不管。


但是從效能和耗費資源的角度來看,使用socket是非常耗費資源的,特別是保持長串連的TCP類型socket,所以在實際的電訊廠商裝置上,這個長串連保持一小段時間後就會被斷開,這樣做也是電訊廠商為了節省和充分利用裝置的資源,而中間有一環的連結斷開之後,雙方就再也無法保持長串連且進行通訊,因為如果僅僅依賴於TCP的長串連,此時伺服器和用戶端是並不知道連結已經被斷開的,所以就會造成下面將要說到的資料丟包問題。除了電訊廠商自己會將裝置的長串連斷開外,還有包括其他原因也將導致連結斷開,例如,電訊廠商的設別斷電或故障等、移動設別接收端本身裝置斷點掉線等諸多複雜的因素存在導致直接依賴於TCP的長串連方案不可行,其次例如Android作業系統本身也是會對TCP的長串連做處理,諸如之前所說的,TCP的socket長串連是非常耗費資源的,這種資源相對於行動裝置來說更加寶貴,所以在一定時間的TCP長串連閑置後,系統也會自動清除裝置上的長串連,以此節省移動設別上的能耗。為了徹底解決長串連的問題,IM技術實際上引入了心跳包的方案,說起來這種實現方案也並不複雜,就是用戶端每個一會兒就要向伺服器發送一個請求報文(這個報文可以是空的,跟伺服器那邊約定好),目的是為了告訴伺服器“我是線上的”,而伺服器在接收心跳請求報文之後同樣需要反饋一個訊息告訴用戶端“我知道了”,通過應用程式層上的不斷進行訊息收發來維持長串連的存在,當用戶端沒有一直沒有收到伺服器的反饋時預設已經掉線,進行相關的商務邏輯處理後將再重連伺服器,同樣伺服器沒有收到用戶端發送來的心跳包時,可以預設用戶端已經掉線,將伺服器上的通訊socket進行關閉回收資源。
其二,用戶端發送資料的丟包問題,在第一個原因中降到電訊廠商和各種各樣的網路情況都會導致發送資料的丟包,陷入以下的這種情境A和B之間同樣經曆1-2-3-4的一個訊息收發流程,但是不幸的是由於各種原因,B返回的訊息在IM伺服器轉寄給A的時候丟失了,此時A並不知道B回複了他訊息,而伺服器也不知道A沒有收到B的回複,這種情況下所帶給使用者的體驗是及其差勁的。


那麼要如何應對這種丟包問題呢?目前想到的一種簡單粗暴的可行方案就伺服器每次向用戶端發送一條訊息都要為這條訊息做一個id的標記,用戶端收到此訊息後需要返回一個回執給伺服器,作為標記當前用戶端已經收到訊息的證明,如果伺服器發送出訊息而遲遲沒有收到伺服器的回執,就把這些訊息作為離線訊息存放到資料庫中,等到用戶端重現上線的時候再將離線訊息推送給用戶端。通過這種方式就可以很好的解決了訊息包發送途中丟包而用戶端和伺服器都不知情的問題。體驗一下子就彪上去了,哢哢哢。

最佳化效能由於IM通訊的即時要求性比較高,伴隨著長串連所耗費的資源也相對比較多,所以在移動平台上的IM通訊用戶端想要效能和體驗上得去,效能最佳化是必不可少的,對此為Android平台上IM最佳化做一些小小的總結,當然不一定很全面,如果你有更好的建議歡迎在評論裡面做補充哈。


小結以上的內容僅僅時平時開發過程中積累的一部分知識和經驗的總結,希望他能協助到其他在尋找資料開發人員,同時,也感謝很多開源項目的貢獻者以及熱愛分享的部落格撰寫者,因為有他們的貢獻和分享才有這篇文章的誕生,才有我在開發過程中的進步。本文的word文檔也會同步到我的github倉庫上, 歡迎拍磚,歡迎轉載,但請註明出處,請勿隨意用於商業用途

Android平台上關於IM的實踐總結

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.