Android推送技術研究

來源:互聯網
上載者:User

標籤:分享   ddms   app   解決   程式碼   lcd   rac   xmpp   通過   

前言

近期研究Android推送的實現, 研究了兩天一夜, 有了一點收穫, 寫下來既為了分享, 也為了吐槽. 須要說明的是有些東西偏底層硬體和通訊行業, 我對這些一竅不通, 僅僅能說說自己的理解.

為什麼要研究Android推送技術?

主要還是畢業設計要做一個即時通訊app, 我是不喜歡做什麼社交app的, 也就象牙塔裡的人想得出來, 說實話有這功夫還不如鑽研一個小技術點, 把一個點研究透徹, 比搞個大而全, 還沒用的東西好得多, 只是誰叫咱們是普通人, 沒得選呢.

Android推送服務的幾種實現方式

現實生活中, 推送服務就像訂雜誌一樣, 僅僅要留下你的地址, 雜誌就能如期送到你手裡, 能夠覺得每一個人都有唯一的一個地址, 但在眼下的網路上, 這是辦不到的, 由於不是每一個人都有一個唯一的地址, server想要給我們推送一條訊息, 必須知道我們的地址, 但server不知道我們在哪.

說到推送服務, 我所知道的實現方案有例如以下幾種:

輪詢

client定期詢問server有沒有新的訊息, 這樣server不用管client的地址是什麼, client來問, 直接告訴它即可.

這樣的方案最簡單, 對於一些不追求即時性的client來說, 非常適合, 僅僅須要把時間間隔設定成幾個小時取一次, 就能非常方便的解決這個問題.

但對於即時通訊產品來說, 這樣的方案全然不能用. 假設即時通訊軟體在網路暢通的情況下發送的訊息要求對方10s內就能收到, 假設用輪詢, 那麼client要每隔5s連一次server, 假設在移動端, 手機的電量和流量非常快就會被消耗殆盡.

SMS通知

這樣的方案在移動端是有可能的, 讓client攔截手機簡訊, server在有新訊息時給使用者的手機號發一條特殊的簡訊, client攔截簡訊後發現是正常簡訊就允許存取, 假設是特殊簡訊就串連server取訊息.

電訊廠商不會配合, 使用者也不會放心, 這方案普通公司玩不起.

長串連

這大概是眼下情況下最佳的方案了, client主動和server建立TCP長串連之後, client定期向server發送心跳包, 有訊息的時候, server直接通過這個已經建立好的TCP串連通知client.

XMPP, MQTT等不算推送技術

在網上搜尋資料的時候, 常常看見XMPP協議實現的Android推送和MQTT協議實現的Android推送, 我個人覺得這兩種說法都怪怪的, XMPP和MQTT二者都是協議, 雖然我不清楚嚴格來講這倆協議工作在哪一層, 可是絕對是在傳輸層之上的, 姑且覺得他倆在TCP/IP五層模型的應用程式層吧, 閉口不提傳輸層的實現, 而是扯應用程式層, 這樣的說法真是令我費解, 所以我個人覺得XMPP, MQTT等等不算推送技術.

關於這個XMPP, 我想非常多人都是參考Openfire和Smack那套東西, 我一年前嘗試用aSmack和Openfire做IM, 只是那個時候什麼都不懂, 做的東西非常爛, 唯一懂的就是Openfire這東西相當老了, 我看有一些開源的推送解決方式都是在這套東西的基礎上改的, 想想這工作量, 挺可怕的.

細說TCP長串連與心跳

長串連方案乍一聽怪怪的, 什麼是長串連? 定時發送心跳, 這和輪詢有什麼差別?

心跳是幹什麼的? 相同是定期和server溝通, 為什麼長串連就比輪詢更加優秀? 手機休眠了TCP串連不會斷掉嗎?

這是我在剛開始研究推送技術的時候的問題, 儘管有些還是沒有非常準確的答案, 但瞭解的大概能夠分享一下, 有什麼錯誤歡迎指出.

什麼是長串連

先說短串連, 短串連是通訊兩方有資料互動時就建立一個串連, 資料發送完畢後。則斷開此串連.


persistent connection


長串連就是大家建立串連之後, 不主動斷開. 兩方互相發送資料, 發完了也不主動中斷連線, 之後有須要發送的資料就繼續通過這個串連發送.

TCP串連在預設的情況下就是所謂的長串連, 也就是說串連兩方都不主動關閉串連, 這個串連就應該一直存在.

可是網路中的情況是複雜的, 這個串連可能會被切斷. 比方client到server的鏈路由於故障斷了, 或者server宕機了, 或者是你家網線被人剪了, 這些都是一些莫名其妙的導致串連被切斷的因素, 還有幾種比較特殊的:

NAT逾時

由於IPv4地址不足, 或者我們想通過無線路由器上網, 我們的裝置可能會處在一個NAT裝置的後面, 生活中最常見的NAT裝置是家用路由器.

NAT裝置會在IP封包通過裝置時改動源/目的IP地址. 對於家用路由器來說, 使用的是網路地址port轉換(NAPT), 它不僅改IP, 還改動TCP和UDP協議的port號, 這樣就能讓內網中的裝置共用同一個外網IP. 舉個範例, NAPT維護一個類似下表的NAT表

內網地址 外網地址
192.168.0.2:5566 120.132.92.21:9200
192.168.0.3:7788 120.132.92.21:9201
192.168.0.3:8888 120.132.92.21:9202

NAT裝置會依據NAT表對出去和進來的資料做改動, 比方將192.168.0.3:8888發出去的封包改成120.132.92.21:9202, 外部就覺得他們是在和120.132.92.21:9202通訊. 同一時候NAT裝置會將120.132.92.21:9202收到的封包的IP和port改成192.168.0.3:8888, 再發給內網的主機, 這樣內部和外部就能雙向通訊了, 但假設當中192.168.0.3:8888 == 120.132.92.21:9202這一映射由於某些原因被NAT裝置淘汰了, 那麼外部裝置就無法直接與192.168.0.3:8888通訊了.

我們的裝置常常是處在NAT裝置的後面, 比方在大學裡的校園網, 查一下自己分配到的IP, 事實上是內網IP, 表明我們在NAT裝置後面, 假設我們在寢室再接個路由器, 那麼我們發出的資料包會多經過一次NAT.

國內移動無線網路電訊廠商在鏈路上一段時間內沒有資料通訊後, 會淘汰NAT表中的相應項, 造成鏈路中斷.

網路狀態切換

行動電話通訊和WIFI網路切換, 網路斷開和連上等情況, 也會使長串連斷開. 這裡原因可能比較多, 但結果無非就是IP變了, 或者被系統通知串連斷了.

DHCP的租期

眼下測試發現安卓系統對DHCP的處理有Bug, DHCP租期到了不會主動續約而且會繼續使用到期IP, 這個問題會造成TCP長串連偶然的斷連.

引自Android智能心跳方案

心跳包的作用

網上非常多文章介紹長串連的時候都說:

由於是長串連, 所以須要定期發送心跳包.
心跳包是用來通知serverclient目前狀態.

提出這些說法的人事實上自己也是一知半解. 這些說法事實上都對, 可是沒有答到點上. 就好像別人問: "你為什麼要去食堂"?

這人回答: "檢查自己還能不能找到食堂". 這個答案說不上錯了, 可是事實上這人是去食堂吃飯的, 證明自己認得路僅僅是個附贈品.

明白一點, TCP長串連本質上不須要心跳包來維持, 大家能夠試一試, 讓兩台電腦連上同一個wifi, 然後讓當中一台做server, 還有一台用一個普通的沒有設定KeepAlive的Socket連上server, 僅僅要兩台電腦別斷網, 路由器也別斷電, DHCP正常續租, 就這麼放著, 過幾個小時再用當中一台電腦通過之前建立的TCP串連給還有一台發訊息, 還有一台肯定能收到.

那為什麼要有心跳包呢?

事實上主要是為了防止上面提到的NAT逾時, 既然一些NAT裝置推斷是否淘汰NAT映射的根據是一定時間沒有資料, 那麼client就主動發一個資料.

當然, 假設不過為了防止NAT逾時, 能夠讓server來發送心跳包給client, 不過這樣做有個弊病就是, 萬一串連斷了, server就再也聯絡不上client了. 所以心跳包必須由client發送, client發現串連斷了, 還能夠嘗試重連server.

所以心跳包的主要作用是防止NAT逾時, 其次是探測串連是否斷開.

鏈路斷開, 沒有寫操作的TCP串連是感知不到的, 除非這個時候發送資料給server, 造成寫逾時, 否則TCP串連不會知道斷開了. 主動kill掉一方的進程, 還有一方會關閉TCP串連, 是系統代進程給server發的FIN. TCP串連就是這樣, 僅僅有明白的收到對方發來的關閉串連的訊息(收到RST也會關閉, 大家都懂), 或者自己意識到發生了寫逾時, 否則它覺得串連還存在.

心跳包的時間間隔

既然心跳包的主要作用是防止NAT逾時, 那麼這個間隔就大有文章了.

發送心跳包勢必要先喚醒裝置, 然後才幹發送, 假設喚醒裝置過於頻繁, 或者直接導致裝置無法休眠, 會大量消耗電量, 並且移動網路下進行網路通訊, 比在wifi下耗電得多. 所以這個心跳包的時間間隔應該盡量的長, 最理想的情況就是根本沒有NAT逾時, 比方剛才我說的兩台在同一個wifi下的電腦, 全然不須要心跳包. 這也就是網上常說的長串連, 慢心跳.

現實是殘酷的, 依據網上的一些說法, 中移動2/3G下, NAT逾時時間為5分鐘, 中國電信3G則大於28分鐘, 理想的情況下, client應當以略小於NAT逾時時間的間隔來發送心跳包.

wifi下, NAT逾時時間都會比較長, 據說寬頻網關一般沒有空暇釋放機制, GCM有些時候在wifi下的心跳比在移動網路下的心跳要快, 可能是由於wifi下連網通訊耗費的電量比移動網路下小.

關於怎樣讓心跳間隔逼近NAT逾時的間隔, 同一時候自己主動適應NAT逾時間隔的變化, 能夠參看

__biz=MzAwNDY1ODY2OQ==&mid=207243549&idx=1&sn=4ebe4beb8123f1b5ab58810ac8bc5994&scene=4#wechat_redirect">Android智能心跳方案.

心跳包和輪詢的差別

心跳包和輪詢看起來類似, 都是client主動聯絡server, 可是差別非常大.

  • 輪詢是為了擷取資料, 而心跳是為了保活TCP串連.

  • 輪詢得越頻繁, 擷取資料就越及時, 心跳的頻繁與否和資料是否及時沒有直接關係

  • 輪詢比心跳能耗更高, 由於一次輪詢須要經過TCP三向交握, 四次揮手, 單次心跳不須要建立和拆除TCP串連.

TCP喚醒Android

這部分內容我僅僅知道結論, 不知道詳細的知識
大家有沒有想過, 手機的簡訊功能和的功能差點兒相同, 為什麼會比簡訊耗電這麼多? 當然不是由於簡訊一條0.1元. 手機簡訊是通過什麼擷取推送的呢?
以下這段出處不明的話或許能夠給大家啟發

首先Android手機有兩個處理器, 一個叫Application Processor(AP), 一個叫Baseband Processor(BP). AP是ARM架構的處理器,用於執行Android系統; BP用於執行即時作業系統(RTOS), 通訊協議棧執行於BP的RTOS之上. 非通話時間, BP的能耗基本上在5mA左右,而AP僅僅要處於非休眠狀態, 能耗至少在50mA以上, 執行圖形運算時會更高. 另外LCD工作時功耗在100mA左右, WIFI也在100mA左右. 一般手機待機時, AP, LCD, WIFI均進入休眠狀態, 這時Android中應用程式的代碼也會停止運行.

Android為了確保應用程式中關鍵代碼的正確運行, 提供了Wake Lock的API, 使得應用程式有許可權通過代碼阻止AP進入休眠狀態. 但假設不領會Android設計者的意圖而濫用Wake Lock API, 為了自身程式在背景正常工作而長時間阻止AP進入休眠狀態, 就會成為待機電池殺手.

全然不是必需操心AP休眠會導致收不到訊息推送. 通訊協議棧運行於BP,一旦收到資料包, BP會將AP喚醒, 喚醒的時間足夠AP運行代碼完畢對收到的資料包的處理過程. 其他的如Connectivity事件觸發時AP相同會被喚醒. 那麼唯一的問題就是程式怎樣運行向server發送心跳包的邏輯. 你顯然不能靠AP來做心跳計時. Android提供的Alarm Manager就是來解決問題的. Alarm應該是BP計時(或其他某個帶石英鐘的晶片。不太確定,但絕對不是AP), 觸發時喚醒AP運行程式碼. 那麼Wake Lock API有啥用呢? 比方心跳包從請求到應答, 比方斷線重連又一次登陸這些關鍵邏輯的運行過程, 就須要Wake Lock來保護. 而一旦一個關鍵邏輯運行成功, 就應該馬上釋放掉Wake Lock了. 兩次心跳請求間隔5到10分鐘, 基本不會怎麼耗電. 除非網路不穩定. 頻繁斷線重連, 那種情況辦法不多.

上面所說的通訊協定, 我猜應該是無線資源控制協議(Radio Resource Control), RRC應該工作在OSI參考模型中的第三層網路層, 而TCP, UDP工作在第四層傳輸層, 上文說的BP, 應該就是手機中的基帶, 也有叫Radio的, 我有點搞不清楚Radio怎麼翻譯. Google在Optimizing Downloads for Efficient Network Access中提到了一個叫Radio State Machine的東西, 我翻譯成無線電波狀態機器, 也不知道正確的翻譯是什麼.

移動網路下, 每個TCP串連底層都應該是有RRC串連, 而RRC串連會喚醒基帶, 基帶會喚醒CPU處理TCP資料, 這是我個人的理解.

至於wifi下怎樣工作, 我臨時沒有找到資料.

上面說了這麼多, 事實上意思就是TCP資料包能喚醒手機. 至於UDP, 我不確定.

而推送中最重要的部分就是讓手機盡量休眠, 僅僅有在server須要它處理資料時才喚醒它, 這正好符合我們的要求.

移動網路下的耗電

Google在Optimizing Downloads for Efficient Network Access中提到了一個叫Radio State Machine的東西.


mobile radio state machine

說的應該就是基帶的工作狀態, 在Radio Standby下差點兒不耗電, 可是一旦有須要處理的事情, 比方手機裡某個app要訪問網路(從上一節能夠猜測: 收到RRC指令也會導致喚醒), 就會進入到Radio Full Power中, 由Standby轉為Full Power這一喚醒過程非常耗電, Full Power下基帶空暇後5s進入Radio Low Power, 假設又空暇12s才進入Standby. 基本的意思就是不要頻繁的喚醒基帶去請求網路, 由於僅僅要一喚醒, 就至少會讓基帶在Full Power下工作5s, 在Low Power下工作12s, 並且喚醒過程非常耗電. 所以在移動網路下, 心跳須要盡量的慢才好, 只是以當前這樣的情況, 想慢下來差點兒不可能.

只是這也帶來另外一個問題, 假如手機裡有10個應用, 每一個應用都發送心跳包, 每一個應用的server都可能喚醒手機, 那手機還休不休眠了?

實際實現遇到的問題

瞭解完了我就開始動手做demo, server使用Apache的Mina, client也用這個

Mina

這個架構挺好用, 就是遇到些非常奇怪的事情, 我兩天前看的, 所以也可能是我自己的問題.

一個是Android端發一個漢字給server, serverfilter崩潰, 發超過一個漢字, clientfilter崩潰, 寫個IoFilter做一下編解碼就好了. 另外User Guide裡面的代碼也有錯誤. 第二個是IoSessionConfig的寫逾時設定了全然不起作用.

小米手機的奇妙Socket

後來又發現client僅僅要在後台超過一定時間, 對socket的寫操作就會變得很詭異, 表現為socket把資料吞了, 告知應用資料已經被對方接收, 可是server什麼都沒收到, 並且server發送的訊息client也收不到. 僅僅要讓app進到前台, 之前消失的資料會一股腦發給server, client會收到server重傳的訊息.

我開始還以為是Android的休眠機制把wifi斷了, 我把各種WifiLock, WakeLock都持有了, 還是出這樣的情況. 後來無意間發現小米針對每一個app都有個後台執行時同意連網的開關, 我把它開啟了, 果然好了一陣子, 後來又開始反覆之前的情況, 我還以為是Mina的IO線程被kill了還是怎麼, 用DDMS看了線程資訊沒問題. 不放心, 又用純Socket實現了client, 還是有問題, 再在之前的基礎上加上1分鐘的心跳, 還是有問題.

小米手機的奇妙bug

這次真是我運氣好, 我又看了一眼後台執行時同意連網的開關, 發現demo app的這個開關剛剛還被我開啟了, 這下又關上了, 我懷疑是小米的這個功能有bug, 我是記得有小米員工提到這東西有server下發白名單的, 我覺得是server下發資料把我的修改給覆蓋了, 我把幾個app的後台連網關了, 重新啟動手機之後, 他們又開了.

最後我改了個10s的心跳間隔, 在心跳的時候, 把後台同意連網關掉, 複現了那個奇妙的socket行為, 大概確定是MIUI的bug.

睡了一覺起來, MIUI的project師聯絡了我, 確認是bug. 順便提醒一下用小米做測試機的開發人員和使用者, 這個bug的暫時解決方式是: 用神隱模式裡的自己定義配置, 把自己想改的設定好即可.

想起一年前什麼都不懂就跑去小米麵試就好笑, 我這水平全然就是坑人, 然而沒想到這次被小米坑了.

我心中最佳的推送技術

RRC那套東西, 你懂的, 基帶Standby模式下也保持著的串連.

參考網址

Understanding the Android “Radio State Machine” for better battery life

__biz=MzAwNDY1ODY2OQ==&mid=207243549&idx=1&sn=4ebe4beb8123f1b5ab58810ac8bc5994&scene=4#wechat_redirect">Android智能心跳方案

q=cache:m9nwCZ-0X1IJ:blog.oasisfeng.com/2013/04/14/dirty-secret-behind-weixin-charge-gate/+&cd=1&hl=zh-CN&ct=clnk&gl=cn">收費事件背後被廣泛忽略的技術細節
android裝置休眠
Optimizing Downloads for Efficient Network Access
關於socket長串連的心跳包
Network address translation
C/C++網路編程中的TCP保活
TCP/IP,http,socket,長串連,短串連――小結。
Android實現推送方式解決方式

轉自【http://www.jianshu.com/p/584707554ed7】

Android推送技術研究

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.