這兩年多一直從事網易雲信 iOS 端 IM SDK的開發,期間不斷有兄弟部門的同事和合做夥伴過來問各類技術細節,乾脆統一介紹下一個IM APP的方方面面,包括技術選型(包括通信方式,網絡鏈接方式,協議選擇)和常見問題。(原文連接:http://www.52im.net/thread-133-1-1.html)php
分享者:項望烽,畢業於浙江大學,目前是網易雲信 iOS 端研發負責人。 html
- 即時通信開發交流羣: 215891622 [推薦]android
- 移動端IM開發推薦文章:《新手入門一篇就夠:從零開發移動端IM》算法
IM通信方式無非兩種選擇:設備直連(P2P)和經過服務器中轉。編程
P2P多見於局域網內聊天工具,典型的應用有:飛鴿傳書、天網Maze(你懂的)等。這類軟件在啓動後通常作兩件事情:緩存
詳細的流程能夠參考飛鴿傳書源碼。可是這種方式在有種種限制和不便:一方面它只適合在線的點對點消息傳輸,對離線,羣組等業務支持不夠。另外一方面因爲 NAT 的存在,使得不一樣局域網內機器互聯難度大大上升,在某些網絡類型(對稱NAT)下沒法創建鏈接。
安全
幾乎全部互聯網IM產品都採用服務器中轉這種方式進行消息傳輸,相對於P2P的方式,它有以下的優勢:服務器
固然它也有本身的問題:服務器架構複雜,併發要求高。微信
IM主流網絡通信技術有兩種:網絡
後者常見於WEB IM系統(固然如今不少WEB IM都是基於WebSocket實現),它的優勢是實現簡單,方便開發上手,問題是流量大,服務器負載較大,消息及時性沒法很好地保證,對大規模的用戶量支持不夠,比較適合小型的IM系統,如小網站的客戶系統。
基於TCP長鏈接則可以更好地支持大批量用戶,問題是客戶端和服務器的實現比較複雜。固然也還有一些變種,以下行使用MQTT進行服務器通知/消息的下發,上行使用HTTP短鏈接進行指令和消息的上傳。這種方式可以保證下行消息/指令的及時性,可是在弱網絡下上行慢的問題仍是比較嚴重。早期的來往就是基於這種方式。
IM協議選擇原則通常是:易於拓展,方便覆蓋各類業務邏輯,同時又比較節約流量。後一點的需求在移動端IM上尤爲重要。常見的協議有:XMPP、SIP、MQTT、私有協議。(更多關於即時通信應用的協議選擇,請參見《如何選擇即時通信應用的數據傳輸格式》:http://www.52im.net/thread-276-1-1.html)
優勢:協議開源,可拓展性強,在各個端(包括服務器)有各類語言的實現,開發者接入方便;
缺點:缺點也是很多,XML表現力弱、有太多冗餘信息、流量大,實際使用時有大量天坑。
SIP協議多用於VOIP相關的模塊,是一種文本協議,因爲我並無實際用過,因此不作評論,但從它是文本協議這一點幾乎能夠判定它的流量不會小。
優勢:協議簡單,流量少;
缺點:它並非一個專門爲IM設計的協議,多使用於推送。
市面上幾乎全部主流IM APP都是是使用私有協議,一個被良好設計的私有協議優勢很是明顯。
優勢:高效,節約流量(通常使用二進制協議),安全性高,難以破解;
缺點:在開發初期沒有現有樣列能夠參考,對於設計者的要求比較高。
一個好的協議須要知足以下條件:高效,簡潔,可讀性好,節約流量,易於拓展,同時又可以匹配當前團隊的技術堆棧。基於如上原則,咱們能夠得出: 若是團隊小,團隊技術在IM上積累不夠能夠考慮使用XMPP或者MQTT+HTTP短鏈接的實現。反之能夠考慮本身設計和實現私有協議。
移動互聯網相對於有線網絡最大特色是:帶寬低,延遲高,丟包率高和穩定性差,流量費用高。因此在私有協議的序列化上通常使用二進制協議,而不是文本協議。
常見的二進制序列化庫有protobuf和MessagePack,固然你也能夠本身實現本身的二進制協議序列化和反序列的過程,好比蘑菇街的TeamTalk。可是前面兩者不管是可拓展性仍是可讀性都完爆TeamTalk(TeamTalk連Variant都不支持,一個int傳輸時固定佔用4個字節),因此大部分狀況下仍是不推薦本身去實現二進制協議的序列化和反序列化過程。
基於TCP的應用層協議通常都分爲包頭和包體(如HTTP),IM協議也不例外。包頭通常用於表示每一個請求/反饋的公共部分,如包長,請求類型,返回碼等。 而包頭則填充不一樣請求/反饋對應的信息。
一個最簡單的包頭能夠定義爲:
1
2
3
4
5
6
7
|
struct
PackHeader
{
int32_t length_;
//包長度
int32_t serial_;
//包序列號
int32_t command_;
//包請求類型
int32_t code_;
//返回碼
};
|
以心跳包爲例,假設當前的serial爲1,心跳包的command爲10,那麼使用MessagePack作序列化時:length=4,serial=1,command=10,code=0,每一個字段各佔一個字節,包體爲空,僅須要4個字節。
固然這是最簡單的一個例子,面對真正的業務邏輯時,包體裏面會須要塞入更多地信息,這個須要開發根據本身的業務邏輯總結公共部分,如爲了兼容加入的協議版本號,爲了負載均衡加入的模塊id等。
上面的內容就是一個IM系統大體的選型過程:服務方式,網絡通信協議,數據通訊協議選擇、協議設計。可是實際開發過程當中還有大量的問題須要處理。
爲了保證協議不容易被破解,市面上幾乎全部主流IM都會對協議進行加密傳輸。常見的流程和HTTPS加密類似:創建鏈接後,客戶端和服務器進行進行協商,最終客戶端得到一個當前Sessino的祕鑰,後續的數據傳輸都經過這個祕鑰進行加解密。通常出於效率的考慮都會採用流式加密,如RC4。而前期協商過程則推薦使用RSA等非對稱加密以增長破解難度。
對iOS APP而言,由於沒有真後臺的存在,APP每次啓動基本都須要一次重連登陸(短期內切換除外),因此如何快速重連、重登就很是重要。
常見優化思路以下:
通常APP實現鏈接保持的方式無非是採用應用層的心跳,經過心跳包的超時和其餘條件(網絡切換)來執行重連操做。那麼問題來了:爲何要使用應用層心跳和如何設計應用層心跳。衆所周知TCP協議是有KEEPALIVE這個設置選項,設置爲KEEPALIVE後,客戶端每隔N秒(默認是7200s)會向服務器發送一個發送心跳包。
但實際操做中咱們更多的是使用應用層心跳。緣由以下:
移動端在實際操做時爲了節約流量和電量通常會在心跳包上作一些小優化:
在移動網絡下,丟包,網絡重連等狀況很是之多,爲了保證消息的可達,通常須要作消息回執和重發機制。參考易信,每條消息會最多會有3次重發,超時時間爲15秒,同時在發送以前會檢測當前鏈接狀態,若是當前鏈接並無正確創建,緩存消息且定時檢查(每隔2秒檢查一次,檢查15次)。因此一條消息在最差的狀況下會有2分鐘左右的重試時間,以保證消息的可達。
由於重發的存在,接受端偶爾會收到重複消息,這種狀況下就須要接收端進行去重。通用的作法是每條消息都戴上本身惟一的message id(通常是uuid)。
IM消息(包括SNS模塊)內包含大量的文件上傳的需求,如何優化文件的上傳就成了一個比較大的主題。
常見有下面這些優化思路:
(原文連接:http://www.52im.net/thread-133-1-1.html)
[1] 網絡編程基礎資料:
《TCP/IP詳解 - 第11章·UDP:用戶數據報協議》
《TCP/IP詳解 - 第17章·TCP:傳輸控制協議》
《TCP/IP詳解 - 第18章·TCP鏈接的創建與終止》
《TCP/IP詳解 - 第21章·TCP的超時與重傳》
《理論經典:TCP協議的3次握手與4次揮手過程詳解》
《理論聯繫實際:Wireshark抓包分析TCP 3次握手、4次揮手過程》
《計算機網絡通信協議關係圖(中文珍藏版)》
《NAT詳解:基本原理、穿越技術(P2P打洞)、端口老化等》
《UDP中一個包的大小最大能多大?》
《Java新一代網絡編程模型AIO原理及Linux系統AIO介紹》
《NIO框架入門(三):iOS與MINA二、Netty4的跨平臺UDP雙向通訊實戰》
《NIO框架入門(四):Android與MINA二、Netty4的跨平臺UDP雙向通訊實戰》
>> 更多同類文章 ……
[2] 有關IM/推送的通訊格式、協議的選擇:
《爲何QQ用的是UDP協議而不是TCP協議?》
《移動端即時通信協議選擇:UDP仍是TCP?》
《如何選擇即時通信應用的數據傳輸格式》
《強列建議將Protobuf做爲你的即時通信應用數據傳輸格式》
《移動端IM開發須要面對的技術問題(含通訊協議選擇)》
《簡述移動端IM開發的那些坑:架構設計、通訊協議和客戶端》
《理論聯繫實際:一套典型的IM通訊協議設計詳解》
《58到家實時消息系統的協議設計等技術實踐分享》
>> 更多同類文章 ……
[3] 有關IM/推送的心跳保活處理:
《Android進程保活詳解:一篇文章解決你的全部疑問》
《Android端消息推送總結:實現原理、心跳保活、遇到的問題等》
《爲什麼基於TCP協議的移動端IM仍然須要心跳保活機制?》
《微信團隊原創分享:Android版微信後臺保活實戰分享(進程保活篇)》
《微信團隊原創分享:Android版微信後臺保活實戰分享(網絡保活篇)》
《移動端IM實踐:實現Android版微信的智能心跳機制》
《移動端IM實踐:WhatsApp、Line、微信的心跳策略分析》
>> 更多同類文章 ……
[4] 有關WEB端即時通信開發:
《新手入門貼:史上最全Web端即時通信技術原理詳解》
《Web端即時通信技術盤點:短輪詢、Comet、Websocket、SSE》
《SSE技術詳解:一種全新的HTML5服務器推送事件技術》
《Comet技術詳解:基於HTTP長鏈接的Web端實時通訊技術》
《WebSocket詳解(一):初步認識WebSocket技術》
《socket.io實現消息推送的一點實踐及思路》
>> 更多同類文章 ……
[5] 有關IM架構設計:
《淺談IM系統的架構設計》
《簡述移動端IM開發的那些坑:架構設計、通訊協議和客戶端》
《一套原創分佈式即時通信(IM)系統理論架構方案》
《從零到卓越:京東客服即時通信系統的技術架構演進歷程》
《蘑菇街即時通信/IM服務器開發之架構選擇》
《騰訊QQ1.4億在線用戶的技術挑戰和架構演進之路PPT》
《微信技術總監談架構:微信之道——大道至簡(演講全文)》
《如何解讀《微信技術總監談架構:微信之道——大道至簡》》
《快速裂變:見證微信強大後臺架構從0到1的演進歷程(一)》
《17年的實踐:騰訊海量產品的技術方法論》
>> 更多同類文章 ……
[6] 有關IM安全的文章:
《即時通信安全篇(一):正確地理解和使用Android端加密算法》
《即時通信安全篇(二):探討組合加密算法在IM中的應用》
《即時通信安全篇(三):經常使用加解密算法與通信安全講解》
《即時通信安全篇(四):實例分析Android中密鑰硬編碼的風險》
《傳輸層安全協議SSL/TLS的Java平臺實現簡介和Demo演示》
《理論聯繫實際:一套典型的IM通訊協議設計詳解(含安全層設計)》
《微信新一代通訊安全解決方案:基於TLS1.3的MMTLS詳解》
《來自阿里OpenIM:打造安全可靠即時通信服務的技術實踐分享》
>> 更多同類文章 ……
[7] 有關實時音視頻開發:
《即時通信音視頻開發(一):視頻編解碼之理論概述》
《即時通信音視頻開發(二):視頻編解碼之數字視頻介紹》
《即時通信音視頻開發(三):視頻編解碼之編碼基礎》
《即時通信音視頻開發(四):視頻編解碼之預測技術介紹》
《即時通信音視頻開發(五):認識主流視頻編碼技術H.264》
《即時通信音視頻開發(六):如何開始音頻編解碼技術的學習》
《即時通信音視頻開發(七):音頻基礎及編碼原理入門》
《即時通信音視頻開發(八):常見的實時語音通信編碼標準》
《即時通信音視頻開發(九):實時語音通信的迴音及迴音消除概述》
《即時通信音視頻開發(十):實時語音通信的迴音消除技術詳解》
《即時通信音視頻開發(十一):實時語音通信丟包補償技術詳解》
《即時通信音視頻開發(十二):多人實時音視頻聊天架構探討》
《即時通信音視頻開發(十三):實時視頻編碼H.264的特色與優點》
《即時通信音視頻開發(十四):實時音視頻數據傳輸協議介紹》
《即時通信音視頻開發(十五):聊聊P2P與實時音視頻的應用狀況》
《即時通信音視頻開發(十六):移動端實時音視頻開發的幾個建議》
《即時通信音視頻開發(十七):視頻編碼H.26四、V8的前世此生》
《簡述開源實時音視頻技術WebRTC的優缺點》
《良心分享:WebRTC 零基礎開發者教程(中文)》
>> 更多同類文章 ……
[8] IM開發綜合文章:
《移動端IM開發須要面對的技術問題》
《開發IM是本身設計協議用字節流好仍是字符流好?》
《請問有人知道語音留言聊天的主流實現方式嗎?》
《IM系統中如何保證消息的可靠投遞(即QoS機制)》
《談談移動端 IM 開發中登陸請求的優化》
《徹底自已開發的IM該如何設計「失敗重試」機制?》
《微信對網絡影響的技術試驗及分析(論文全文)》
《即時通信系統的原理、技術和應用(技術論文)》
《開源IM工程「蘑菇街TeamTalk」的現狀:一場虎頭蛇尾的開源秀》
>> 更多同類文章 ……
[9] 開源移動端IM技術框架資料:
《開源移動端IM技術框架MobileIMSDK:快速入門》
《開源移動端IM技術框架MobileIMSDK:常見問題解答》
《開源移動端IM技術框架MobileIMSDK:壓力測試報告》
>> 更多同類文章 ……
[10] 有關推送技術的文章:
《iOS的推送服務APNs詳解:設計思路、技術原理及缺陷等》
《Android端消息推送總結:實現原理、心跳保活、遇到的問題等》
《掃盲貼:認識MQTT通訊協議》
《一個基於MQTT通訊協議的完整Android推送Demo》
《求教android消息推送:GCM、XMPP、MQTT三種方案的優劣》
《移動端實時消息推送技術淺析》
《掃盲貼:淺談iOS和Android後臺實時消息推送的原理和區別》
《絕對乾貨:基於Netty實現海量接入的推送服務技術要點》
《移動端IM實踐:谷歌消息推送服務(GCM)研究(來自微信)》
《爲什麼微信、QQ這樣的IM工具不使用GCM服務推送消息?》
>> 更多同類文章 ……
[11] 更多即時通信技術好文分類: