iOS即時通訊,從入門到“放棄”?

發表於2017-01-05
112702646-9345b2e50209bd68
前言
  • 本文會用例項的方式,將iOS各種IM的方案都簡單的實現一遍。並且提供一些選型、實現細節以及優化的建議。
  • 注:文中的所有的程式碼示例,在github中都有demo:
    iOS即時通訊,從入門到“放棄”?(demo)
    可以開啟專案先預覽效果,對照著進行閱讀。

言歸正傳,首先我們來總結一下我們去實現IM的方式

第一種方式,使用第三方IM服務

對於短平快的公司,完全可以採用第三方SDK來實現。國內IM的第三方服務商有很多,類似雲信、環信、融雲、LeanCloud,當然還有其它的很多,這裡就不一一舉例了,感興趣的小夥伴可以自行查閱下。

  • 第三方服務商IM底層協議基本上都是TCP。他們的IM方案很成熟,有了它們,我們甚至不需要自己去搭建IM後臺,什麼都不需要去考慮。
    如果你足夠懶,甚至連UI都不需要自己做,這些第三方有各自一套IM的UI,拿來就可以直接用。真可謂3分鐘整合…
  • 但是缺點也很明顯,定製化程度太高,很多東西我們不可控。當然還有一個最最重要的一點,就是太貴了…作為真正社交為主打的APP,僅此一點,就足以讓我們望而卻步。當然,如果IM對於APP只是一個輔助功能,那麼用第三方服務也無可厚非。
另外一種方式,我們自己去實現

我們自己去實現也有很多選擇:
1)首先面臨的就是傳輸協議的選擇,TCP還是UDP
2)其次是我們需要去選擇使用哪種聊天協議:

  • 基於Scoket或者WebScoket或者其他的私有協議、
  • MQTT
  • 還是廣為人詬病的XMPP?

3)我們是自己去基於OS底層Socket進行封裝還是在第三方框架的基礎上進行封裝?
4)傳輸資料的格式,我們是用Json、還是XML、還是谷歌推出的ProtocolBuffer
5)我們還有一些細節問題需要考慮,例如TCP的長連線如何保持,心跳機制,Qos機制,重連機制等等…當然,除此之外,我們還有一些安全問題需要考慮。

一、傳輸協議的選擇

接下來我們可能需要自己考慮去實現IM,首先從傳輸層協議來說,我們有兩種選擇:TCP or UDP

122702646-2d6dc11cbf1ddabb

這個問題已經被討論過無數次了,對深層次的細節感興趣的朋友可以看看這篇文章:

  • 移動端IM/推送系統的協議選型:UDP還是TCP?這裡我們直接說結論吧:對於小公司或者技術不那麼成熟的公司,IM一定要用TCP來實現,因為如果你要用UDP的話,需要做的事太多。當然QQ就是用的UDP協議,當然不僅僅是UDP,騰訊還用了自己的私有協議,來保證了傳輸的可靠性,杜絕了UDP下各種資料丟包,亂序等等一系列問題。
    總之一句話,如果你覺得團隊技術很成熟,那麼你用UDP也行,否則還是用TCP為好。
二、我們來看看各種聊天協議

首先我們以實現方式來切入,基本上有以下四種實現方式:

  1. 基於Scoket原生:代表框架 CocoaAsyncSocket
  2. 基於WebScoket:代表框架 SocketRocket
  3. 基於MQTT:代表框架 MQTTKit
  4. 基於XMPP:代表框架 XMPPFramework

當然,以上四種方式我們都可以不使用第三方框架,直接基於OS底層Scoket去實現我們的自定義封裝。下面我會給出一個基於Scoket原生而不使用框架的例子,供大家參考一下。

首先需要搞清楚的是,其中MQTTXMPP為聊天協議,它們是最上層的協議,而WebScoket是傳輸通訊協議,它是基於Socket封裝的一個協議。而通常我們所說的騰訊IM的私有協議,就是基於WebScoket或者Scoket原生進行封裝的一個聊天協議。

具體這3種聊天協議的對比優劣如下:

132702646-c225bb81f580718d

協議優劣對比.png

所以說到底,iOS要做一個真正的IM產品,一般都是基於Scoket或者WebScoket等,再之上加上一些私有協議來保證的。

1.我們先不使用任何框架,直接用OS底層Socket來實現一個簡單的IM。

我們客戶端的實現思路也是很簡單,建立Socket,和伺服器的Socket對接上,然後開始傳輸資料就可以了。

  • 我們學過c/c++或者java這些語言,我們就知道,往往任何教程,最後一章都是講Socket程式設計,而Socket是什麼呢,簡單的來說,就是我們使用TCP/IP 或者UDP/IP協議的一組程式設計介面。如下圖所示:
    142702646-5eaf55a2a5469d4e

    我們在應用層,使用socket,輕易的實現了程式之間的通訊(跨網路的)。想想,如果沒有socket,我們要直面TCP/IP協議,我們需要去寫多少繁瑣而又重複的程式碼。

    如果有對socket概念仍然有所困惑的,可以看看這篇文章:
    從問題看本質,socket到底是什麼?

我們接著可以開始著手去實現IM了,首先我們不基於任何框架,直接去呼叫OS底層-基於C的BSD Socket去實現,它提供了這樣一組介面:

讓我們可以對socket進行各種操作,首先我們來用它寫個客戶端。總結一下,簡單的IM客戶端需要做如下4件事:

  1. 客戶端呼叫 socket(…) 建立socket;
  2. 客戶端呼叫 connect(…) 向伺服器發起連線請求以建立連線;
  3. 客戶端與伺服器建立連線之後,就可以通過send(…)/receive(…)向客戶端傳送或從客戶端接收資料;
  4. 客戶端呼叫 close 關閉 socket;

根據上面4條大綱,我們封裝了一個名為TYHSocketManager的單例,來對socket相關方法進行呼叫:

TYHSocketManager.h

TYHSocketManager.m

如上所示:

  • 我們呼叫了initScoket方法,利用CreateClinetSocket方法了一個scoket,就是就是呼叫了socket函式:
  • 然後呼叫了ConnectionToServer函式與伺服器連線,IP地址為127.0.0.1也就是本機localhost和埠6969相連。在該函式中,我們繫結了一個sockaddr_in型別的結構體,該結構體內容如下:

    裡面包含了一些,我們需要連線的服務端的scoket的一些基本引數,具體賦值細節可以見註釋。
  • 連線成功之後,我們就可以呼叫send函式和recv函式進行訊息收發了,在這裡,我新開闢了一個常駐執行緒,在這個執行緒中一個死迴圈裡去不停的呼叫recv函式,這樣服務端有訊息傳送過來,第一時間便能被接收到。

就這樣客戶端便簡單的可以用了,接著我們來看看服務端的實現。

一樣,我們首先對服務端需要做的工作簡單的總結下:
  1. 伺服器呼叫 socket(…) 建立socket;
  2. 伺服器呼叫 listen(…) 設定緩衝區;
  3. 伺服器通過 accept(…)接受客戶端請求建立連線;
  4. 伺服器與客戶端建立連線之後,就可以通過 send(…)/receive(…)向客戶端傳送或從客戶端接收資料;
  5. 伺服器呼叫 close 關閉 socket;
接著我們就可以具體去實現了

OS底層的函式是支援我們去實現服務端的,但是我們一般不會用iOS去這麼做(試問真正的應用場景,有誰用iOSscoket伺服器麼…),如果還是想用這些函式去實現服務端,可以參考下這篇文章: 深入淺出Cocoa-iOS網路程式設計之Socket

在這裡我用node.js去搭了一個簡單的scoket伺服器。原始碼如下:

看到這不懂node.js的朋友也不用著急,在這裡你可以使用任意語言c/c++/java/oc等等去實現後臺,這裡node.js僅僅是樓主的一個選擇,為了讓我們來驗證之前寫的客戶端scoket的效果。如果你不懂node.js也沒關係,你只需要把上述樓主寫的相關程式碼複製貼上,如果你本機有node的直譯器,那麼直接在終端進入該原始碼檔案目錄中輸入:

即可執行該指令碼(fileName為儲存原始碼的檔名)。

我們來看看執行效果:

152702646-dd635641474fa29e

handle2.gif

伺服器執行起來了,並且監聽著6969埠。
接著我們用之前寫的iOS端的例子。客戶端列印顯示連線成功,而我們執行的伺服器也列印了連線成功。接著我們發了一條訊息,服務端成功的接收到了訊息後,把該訊息再傳送回客戶端,繞了一圈客戶端又收到了這條訊息。至此我們用OS底層scoket實現了簡單的IM。

大家看到這是不是覺得太過簡單了?
當然簡單,我們僅僅是實現了Scoket的連線,資訊的傳送與接收,除此之外我們什麼都沒有做,現實中,我們需要做的處理遠不止於此,我們先接著往下看。接下來,我們就一起看看第三方框架是如何實現IM的。

162702646-bddc7341d9eda6ae

分割圖.png
2.我們接著來看看基於Socket原生的CocoaAsyncSocket:

這個框架實現了兩種傳輸協議TCPUDP,分別對應GCDAsyncSocket類和GCDAsyncUdpSocket,這裡我們重點講GCDAsyncSocket

這裡Socket伺服器延續上一個例子,因為同樣是基於原生Scoket的框架,所以之前的Node.js的服務端,該例仍然試用。這裡我們就只需要去封裝客戶端的例項,我們還是建立一個TYHSocketManager單例。

TYHSocketManager.h

TYHSocketManager.m

這個框架使用起來也十分簡單,它基於Scoket往上進行了一層封裝,提供了OC的介面給我們使用。至於使用方法,大家看看註釋應該就能明白,這裡唯一需要說的一點就是這個方法:

這個方法的作用就是去讀取當前訊息佇列中的未讀訊息。記住,這裡不呼叫這個方法,訊息回撥的代理是永遠不會被觸發的。而且必須是tag相同,如果tag不同,這個收到訊息的代理也不會被處罰。
我們呼叫一次這個方法,只能觸發一次讀取訊息的代理,如果我們呼叫的時候沒有未讀訊息,它就會等在那,直到訊息來了被觸發。一旦被觸發一次代理後,我們必須再次呼叫這個方法,否則,之後的訊息到了仍舊無法觸發我們讀取訊息的代理。就像我們在例子中使用的那樣,在每次讀取到訊息之後我們都去呼叫:

除此之外,我們還需要說的是這個超時timeout
這裡如果設定10秒,那麼就只能監聽10秒,10秒過後呼叫是否續時的代理方法:

如果我們選擇不續時,那麼10秒到了還沒收到訊息,那麼Scoket會自動斷開連線。看到這裡有些小夥伴要吐槽了,怎麼一個方法設計的這麼麻煩,當然這裡這麼設計是有它的應用場景的,我們後面再來細講。

我們同樣來執行看看效果:
172702646-d92af23f6589b863
handle3.gif

至此我們也用CocoaAsyncSocket這個框架實現了一個簡單的IM。

162702646-bddc7341d9eda6ae

分割圖.png
3.接著我們繼續來看看基於webScoket的IM:

這個例子我們會把心跳,斷線重連,以及PingPong機制進行簡單的封裝,所以我們先來談談這三個概念:

首先我們來談談什麼是心跳

簡單的來說,心跳就是用來檢測TCP連線的雙方是否可用。那又會有人要問了,TCP不是本身就自帶一個KeepAlive機制嗎?
這裡我們需要說明的是TCP的KeepAlive機制只能保證連線的存在,但是並不能保證客戶端以及服務端的可用性.比如會有以下一種情況:

某臺伺服器因為某些原因導致負載超高,CPU 100%,無法響應任何業務請求,但是使用 TCP 探針則仍舊能夠確定連線狀態,這就是典型的連線活著但業務提供方已死的狀態。

這個時候心跳機制就起到作用了:

  • 我們客戶端發起心跳Ping(一般都是客戶端),假如設定在10秒後如果沒有收到回撥,那麼說明伺服器或者客戶端某一方出現問題,這時候我們需要主動斷開連線。
  • 服務端也是一樣,會維護一個socket的心跳間隔,當約定時間內,沒有收到客戶端發來的心跳,我們會知道該連線已經失效,然後主動斷開連線。

參考文章:為什麼說基於TCP的移動端IM仍然需要心跳保活?

其實做過IM的小夥伴們都知道,我們真正需要心跳機制的原因其實主要是在於國內運營商NAT超時。

那麼究竟什麼是NAT超時呢?

原來這是因為IPV4引起的,我們上網很可能會處在一個NAT裝置(無線路由器之類)之後。
NAT裝置會在IP封包通過裝置時修改源/目的IP地址. 對於家用路由器來說, 使用的是網路地址埠轉換(NAPT), 它不僅改IP, 還修改TCP和UDP協議的埠號, 這樣就能讓內網中的裝置共用同一個外網IP. 舉個例子, NAPT維護一個類似下表的NAT表:

182702646-cefd86afd8b99939

NAT對映

NAT裝置會根據NAT表對出去和進來的資料做修改, 比如將192.168.0.3:8888發出去的封包改成120.132.92.21:9202, 外部就認為他們是在和120.132.92.21:9202通訊. 同時NAT裝置會將120.132.92.21:9202收到的封包的IP和埠改成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表中的對應項, 造成鏈路中斷。

而國內的運營商一般NAT超時的時間為5分鐘,所以通常我們心跳設定的時間間隔為3-5分鐘。

接著我們來講講PingPong機制:

很多小夥伴可能又會感覺到疑惑了,那麼我們在這心跳間隔的3-5分鐘如果連線假線上(例如在地鐵電梯這種環境下)。那麼我們豈不是無法保證訊息的即時性麼?這顯然是我們無法接受的,所以業內的解決方案是採用雙向的PingPong機制。

192702646-6e51be4cf4ba7b11

當服務端發出一個Ping,客戶端沒有在約定的時間內返回響應的ack,則認為客戶端已經不線上,這時我們Server端會主動斷開Scoket連線,並且改由APNS推送的方式傳送訊息。
同樣的是,當客戶端去傳送一個訊息,因為我們遲遲無法收到服務端的響應ack包,則表明客戶端或者服務端已不線上,我們也會顯示訊息傳送失敗,並且斷開Scoket連線。

還記得我們之前CocoaSyncSockt的例子所講的獲取訊息超時就斷開嗎?其實它就是一個PingPong機制的客戶端實現。我們每次可以在傳送訊息成功後,呼叫這個超時讀取的方法,如果一段時間沒收到伺服器的響應,那麼說明連線不可用,則斷開Scoket連線

最後就是重連機制:

理論上,我們自己主動去斷開的Scoket連線(例如退出賬號,APP退出到後臺等等),不需要重連。其他的連線斷開,我們都需要進行斷線重連。
一般解決方案是嘗試重連幾次,如果仍舊無法重連成功,那麼不再進行重連。
接下來的WebScoket的例子,我會封裝一個重連時間指數級增長的一個重連方式,可以作為一個參考。

言歸正傳,我們看完上述三個概念之後,我們來講一個WebScoket最具代表性的一個第三方框架SocketRocket

我們首先來看看它對外封裝的一些方法:

方法也很簡單,分為兩個部分:

  • 一部分為SRWebSocket的初始化,以及連線,關閉連線,傳送訊息等方法。
  • 另一部分為SRWebSocketDelegate,其中包括一些回撥:
    收到訊息的回撥,連線失敗的回撥,關閉連線的回撥,收到pong的回撥,是否需要把data訊息轉換成string的代理方法。
接著我們還是舉個例子來實現以下,首先來封裝一個TYHSocketManager單例:

TYHSocketManager.h

TYHSocketManager.m

.m檔案有點長,大家可以參照github中的demo進行閱讀,這回我們新增了一些細節的東西了,包括一個簡單的心跳,重連機制,還有webScoket封裝好的一個pingpong機制。
程式碼非常簡單,大家可以配合著註釋讀一讀,應該很容易理解。
需要說一下的是這個心跳機制是一個定時的間隔,往往我們可能會有更復雜實現,比如我們正在傳送訊息的時候,可能就不需要心跳。當不在傳送的時候在開啟心跳之類的。微信有一種更高階的實現方式,有興趣的小夥伴可以看看:
微信的智慧心跳實現方式

還有一點需要說的就是這個重連機制,demo中我採用的是2的指數級別增長,第一次立刻重連,第二次2秒,第三次4秒,第四次8秒…直到大於64秒就不再重連。而任意的一次成功的連線,都會重置這個重連時間。

最後一點需要說的是,這個框架給我們封裝的webscoket在呼叫它的sendPing方法之前,一定要判斷當前scoket是否連線,如果不是連線狀態,程式則會crash

客戶端的實現就大致如此,接著同樣我們需要實現一個服務端,來看看實際通訊效果。

webScoket服務端實現

在這裡我們無法沿用之前的node.js例子了,因為這並不是一個原生的scoket,這是webScoket,所以我們服務端同樣需要遵守webScoket協議,兩者才能實現通訊。
其實這裡實現也很簡單,我採用了node.jsws模組,只需要用npm去安裝ws即可。
什麼是npm呢?舉個例子,npm之於Node.js相當於cocospod至於iOS,它就是一個擴充模組的一個管理工具。如果不知道怎麼用的可以看看這篇文章:npm的使用

我們進入當前指令碼目錄,輸入終端命令,即可安裝ws模組:

大家如果懶得去看npm的小夥伴也沒關係,直接下載github中的 WSServer.js這個檔案執行即可。
該原始檔程式碼如下:

程式碼沒幾行,理解起來很簡單。
就是監聽了本機6969埠,如果客戶端連線了,列印lient connected,並且向客戶端傳送:你是第幾位。
如果收到客戶端訊息後,列印訊息,並且向客戶端傳送這條收到的訊息。

接著我們同樣來執行一下看看效果:

202702646-410b24e854bc4a71

執行我們可以看到,主動去斷開的連線,沒有去重連,而server端斷開的,我們開啟了重連。感興趣的朋友可以下載demo實際執行一下。

162702646-bddc7341d9eda6ae

分割圖.png
4.我們接著來看看MQTT:

MQTT是一個聊天協議,它比webScoket更上層,屬於應用層。
它的基本模式是簡單的釋出訂閱,也就是說當一條訊息發出去的時候,誰訂閱了誰就會受到。其實它並不適合IM的場景,例如用來實現有些簡單IM場景,卻需要很大量的、複雜的處理。
比較適合它的場景為訂閱釋出這種模式的,例如微信的實時共享位置,滴滴的地圖上小車的移動、客戶端推送等功能。

首先我們來看看基於MQTT協議的框架-MQTTKit:
這個框架是c來寫的,把一些方法公開在MQTTKit類中,對外用OC來呼叫,我們來看看這個類:

這個類一共分為4個部分:初始化、連線、釋出、訂閱,具體方法的作用可以先看看方法名理解下,我們接著來用這個框架封裝一個例項。

同樣,我們封裝了一個單例MQTTManager
MQTTManager.h

MQTTManager.m

實現程式碼很簡單,需要說一下的是:
1)當我們連線成功了,我們需要去訂閱自己clientID的訊息,這樣才能收到發給自己的訊息。
2)其次是這個框架為我們實現了一個QOS機制,那麼什麼是QOS呢?

QoS(Quality of Service,服務質量)指一個網路能夠利用各種基礎技術,為指定的網路通訊提供更好的服務能力, 是網路的一種安全機制, 是用來解決網路延遲和阻塞等問題的一種技術。

在這裡,它提供了三個選項:

分別對應最多傳送一次,至少傳送一次,精確只傳送一次。

  • QOS(0),最多傳送一次:如果訊息沒有傳送過去,那麼就直接丟失。
  • QOS(1),至少傳送一次:保證訊息一定傳送過去,但是發幾次不確定。
  • QOS(2),精確只傳送一次:它內部會有一個很複雜的傳送機制,確保訊息送到,而且只傳送一次。

更詳細的關於該機制可以看看這篇文章:MQTT協議筆記之訊息流QOS

同樣的我們需要一個用MQTT協議實現的服務端,我們還是node.js來實現,這次我們還是需要用npm來新增一個模組mosca
我們來看看服務端程式碼:
MQTTServer.js

服務端程式碼沒幾行,開啟了一個服務,並且監聽本機6969埠。並且監聽了客戶端連線、釋出訊息等狀態。

接著我們同樣來執行一下看看效果:

212702646-beec3a4437a7d6db

至此,我們實現了一個簡單的MQTT封裝。

5.XMPP:XMPPFramework框架

結果就是並沒有XMPP…因為個人感覺XMPP對於IM來說實在是不堪重用。僅僅只能作為一個玩具demo,給大家練練手。網上有太多XMPP的內容了,相當一部分用openfire來做服務端,這一套東西實在是太老了。還記得多年前,樓主初識IM就是用的這一套東西…
如果大家仍然感興趣的可以看看這篇文章:iOS 的 XMPPFramework 簡介。這裡就不舉例贅述了。

三、關於IM傳輸格式的選擇:

引用陳宜龍大神文章(iOS程式犭袁 )中一段:
使用 ProtocolBuffer 減少 Payload
滴滴叫車40%;
攜程之前分享過,說是採用新的Protocol Buffer資料格式+Gzip壓縮後的Payload大小降低了15%-45%。資料序列化耗時下降了80%-90%。

採用高效安全的私有協議,支援長連線的複用,穩定省電省流量
【高效】提高網路請求成功率,訊息體越大,失敗機率隨之增加。
【省流量】流量消耗極少,省流量。一條訊息資料用Protobuf序列化後的大小是 JSON 的1/10、XML格式的1/20、是二進位制序列化的1/10。同 XML 相比, Protobuf 效能優勢明顯。它以高效的二進位制方式儲存,比 XML 小 3 到 10 倍,快 20 到 100 倍。
【省電】省電
【高效心跳包】同時心跳包協議對IM的電量和流量影響很大,對心跳包協議上進行了極簡設計:僅 1 Byte 。
【易於使用】開發人員通過按照一定的語法定義結構化的訊息格式,然後送給命令列工具,工具將自動生成相關的類,可以支援java、c++、python、Objective-C等語言環境。通過將這些類包含在專案中,可以很輕鬆的呼叫相關方法來完成業務訊息的序列化與反序列化工作。語言支援:原生支援c++、java、python、Objective-C等多達10餘種語言。 2015-08-27 Protocol Buffers v3.0.0-beta-1中釋出了Objective-C(Alpha)版本, 2016-07-28 3.0 Protocol Buffers v3.0.0正式版釋出,正式支援 Objective-C。
【可靠】微信和手機 QQ 這樣的主流 IM 應用也早已在使用它(採用的是改造過的Protobuf協議)

222702646-3c314239bfa0baea

如何測試驗證 Protobuf 的高效能?
對資料分別操作100次,1000次,10000次和100000次進行了測試,
縱座標是完成時間,單位是毫秒,
反序列化
序列化
位元組長度

232702646-f6b9826dc377a278

242702646-9671c7c62a2d9462
252702646-3768d8ba7cb21291

資料來源

262702646-356bf2a501d04177

資料來自:專案 thrift-protobuf-compare,測試項為 Total Time,也就是 指一個物件操作的整個時間,包括建立物件,將物件序列化為記憶體中的位元組序列,然後再反序列化的整個過程。從測試結果可以看到 Protobuf 的成績很好.
缺點:
可能會造成 APP 的包體積增大,通過 Google 提供的指令碼生成的 Model,會非常“龐大”,Model 一多,包體積也就會跟著變大。
如果 Model 過多,可能導致 APP 打包後的體積驟增,但 IM 服務所使用的 Model 非常少,比如在 ChatKit-OC 中只用到了一個 Protobuf 的 Model:Message物件,對包體積的影響微乎其微。
在使用過程中要合理地權衡包體積以及傳輸效率的問題,據說去哪兒網,就曾經為了減少包體積,進而減少了 Protobuf 的使用。

綜上所述,我們選擇傳輸格式的時候:ProtocolBuffer > Json > XML

如果大家對ProtocolBuffer用法感興趣可以參考下這兩篇文章:
ProtocolBuffer for Objective-C 執行環境配置及使用
iOS之ProtocolBuffer搭建和示例demo

三、IM一些其它問題
1.IM的可靠性:

我們之前穿插在例子中提到過:
心跳機制、PingPong機制、斷線重連機制、還有我們後面所說的QOS機制。這些被用來保證連線的可用,訊息的即時與準確的送達等等。
上述內容保證了我們IM服務時的可靠性,其實我們能做的還有很多:比如我們在大檔案傳輸的時候使用分片上傳、斷點續傳、秒傳技術等來保證檔案的傳輸。

2.安全性:

我們通常還需要一些安全機制來保證我們IM通訊安全。
例如:防止 DNS 汙染、帳號安全、第三方伺服器鑑權、單點登入等等

3.一些其他的優化:

類似微信,伺服器不做聊天記錄的儲存,只在本機進行快取,這樣可以減少對服務端資料的請求,一方面減輕了伺服器的壓力,另一方面減少客戶端流量的消耗。
我們進行http連線的時候儘量採用上層API,類似NSUrlSession。而網路框架儘量使用AFNetWorking3。因為這些上層網路請求都用的是HTTP/2 ,我們請求的時候可以複用這些連線。

更多優化相關內容可以參考參考這篇文章:
IM 即時通訊技術在多應用場景下的技術實現,以及效能調優

四、音視訊通話

IM應用中的實時音視訊技術,幾乎是IM開發中的最後一道高牆。原因在於:實時音視訊技術 = 音視訊處理技術 + 網路傳輸技術 的橫向技術應用集合體,而公共網際網路不是為了實時通訊設計的。
實時音視訊技術上的實現內容主要包括:音視訊的採集、編碼、網路傳輸、解碼、播放等環節。這麼多項並不簡單的技術應用,如果把握不當,將會在在實際開發過程中遇到一個又一個的坑。

因為樓主自己對這塊的技術理解很淺,所以引用了一個系列的文章來給大家一個參考,感興趣的朋友可以看看:
即時通訊音視訊開發(一):視訊編解碼之理論概述
即時通訊音視訊開發(二):視訊編解碼之數字視訊介紹
即時通訊音視訊開發(三):視訊編解碼之編碼基礎
即時通訊音視訊開發(四):視訊編解碼之預測技術介紹
即時通訊音視訊開發(五):認識主流視訊編碼技術H.264
即時通訊音視訊開發(六):如何開始音訊編解碼技術的學習
即時通訊音視訊開發(七):音訊基礎及編碼原理入門
即時通訊音視訊開發(八):常見的實時語音通訊編碼標準
即時通訊音視訊開發(九):實時語音通訊的迴音及迴音消除概述
即時通訊音視訊開發(十):實時語音通訊的迴音消除技術詳解
即時通訊音視訊開發(十一):實時語音通訊丟包補償技術詳解
即時通訊音視訊開發(十二):多人實時音視訊聊天架構探討
即時通訊音視訊開發(十三):實時視訊編碼H.264的特點與優勢
即時通訊音視訊開發(十四):實時音視訊資料傳輸協議介紹
即時通訊音視訊開發(十五):聊聊P2P與實時音視訊的應用情況
即時通訊音視訊開發(十六):移動端實時音視訊開發的幾個建議
即時通訊音視訊開發(十七):視訊編碼H.264、V8的前世今生

寫在最後:

本文內容為原創,且僅代表樓主現階段的一些思想,如果有什麼錯誤,歡迎指正~

相關文章