跟我一塊兒開發商業級IM(1)——技術選型及協議定義

技術選型及協議定義Banner



1php


寫在前面html

終於能夠開始寫這個系列的文章了,本系列文章預計將分爲13篇,因爲IM涉及的知識點稍複雜,因此每一個知識點都會單獨用一篇文章來闡述,儘可能講透徹,方便你們理解。  java


2android


靈魂拷問git

爲何須要寫這個系列的文章呢?
可能你們會問,有了以前的NettyChat[1]開源一個自用的Android IM庫,基於Netty+TCP+Protobuf實現[2],爲何還須要寫這個系列的文章呢?主要是由於一開始開源NettyChat和發佈文章的時候,旨在起一種拋磚引玉的做用,帶領你們入門IM而已。並且一篇文章難以闡述全部的知識點,加上NettyChat也是一個Demo,有些代碼寫得不嚴謹。一年多以來,從羣裏的反饋、文章的評論能夠看到你們對這一塊知識有很多的需求,你們去集成NettyChat到本身項目裏也比較麻煩,網上也缺少完整的IM實現,大可能是零零碎碎的知識點。因此打算從零開始,手把手教你們實現本身的IM系統。

對比NettyChat有什麼新增的功能和優化?
根據你們的反饋,支持TCP/WebSocket、Protobuf/Json等。優化消息重發管理器,再也不是一條消息一個Timer實現(嚴重浪費資源,影響程序性能)。另外,優化代碼結構,提高可擴展性、可維護性等。

項目包含服務端代碼嗎?
這也是從新寫本系列文章的重要緣由,在本系列文章中,將包含Java服務端代碼及Android代碼,至於IOS,後續有時間會增長。文章完成後,會在Github[3]開源三個項目,分別是:
1.ims_kula[Android IM Service SDK]github

2.kulachat_server[Java 服務端]3.KulaChat[Android 客戶端]


web

爲何項目叫「Kula」?
其實就是一時興起,Kula是做者比較喜歡的SNK拳皇系列裏的一個角色,沒什麼具體含義。附上Kula高清圖:
spring

Kula


大綱如圖:數據庫

跟我一塊兒開發商業級IM——大綱


本系列文章將包含:apache

技術選型及協議定義接口定義及封裝粘包/粘包處理之自定義消息編解碼器長鏈接穩定性之鏈接及重連心跳機制消息重發機制離線消息機制消息順序控制數據庫表設計單聊實現羣聊實現系統消息實現UI封裝

本文爲第一篇:技術選型及協議定義


3


項目架構

首先,講一下項目總體架構以及使用到的開源框架。根據羣裏小夥伴的建議以及你們對JavaKotlin的熟悉程度,Android端開發語言仍是採用Java,後續有時間會考慮用Kotlin開發一個版本。

因爲項目未完成,目前是邊寫文章邊寫代碼的方式,因此在後續項目完成後,會專門寫一篇文章介紹項目架構,包括Android客戶端Java服務端

Android客戶端 項目總體採用MVP架構,用到的開源庫以下:

RxJava 2.2.8RxAndroid 2.1.1Retrofit 2.8.1GreenDao 3.3.0Dagger 2.27Butterknife 10.2.1Glide 4.11.0StatusBarUtil 1.5.1BaseRecyclerViewAdapterHelper 3.0.4AutoSize 1.2.1Fastjson 1.1.71.androidLogginInterceptor 3.1.0-rc5RxPermissions 0.10.2Toasty 1.4.2Background 1.6.5EventCenter 1.0.1NiceImageView 1.0.5More...

Java服務端
還在開發中,就不一一列舉了。
感謝以上開源庫的做者。

如下的通訊協議選型、傳輸協議選型、通訊框架選型在開源一個自用的Android IM庫,基於Netty+TCP+Protobuf實現[4]文章中有說明過,但既然打算從新寫本系列的文章,就在此從新講解一下,一來加入本身新的理解,二來能夠整合到本系列文章裏。

如下所涉及的原理和理論知識,因爲篇幅緣由及做者水平有限,沒辦法詳細闡述。本系列文章的着重點在於教你們怎麼去實現本身的IM系統,至於偏理論的知識,做者幫你們找了一下原文連接,感興趣的能夠跳轉原文閱讀。同時感謝如下文章的做者。


4


通訊協議選型

經常使用的通訊協議有如下幾種,分別簡單地講講每種通訊協議的優缺點及適用場景。

UDP簡單概述
UDP是一個面向報文的、非鏈接的協議,也就是無鏈接的。即發送數據前,雙方無需創建鏈接,數據發送完畢後,也無需斷開鏈接(沒有鏈接可斷開)。這樣一來,減小了鏈接和斷開鏈接的開銷(無需像TCP同樣鏈接時須要三次握手,斷開鏈接時須要四次揮手)。同時,UDP不存在擁塞機制,即網絡擁塞時,不會使源主機的發送速率下降。另外,UDP一個很大的特色就是盡最大努力交付(即不保證交付),也就是可能會存在丟包、亂序等狀況。總的來講,UDP是一個不可靠的協議
優勢效率高
因爲UDP在發送數據前,無需創建鏈接,而且沒有TCP一系列的確認機制、重傳機制、擁塞機制等,因此在數據傳輸上,效率較高。
開銷小
UDP首部開銷僅8個字節(源端口[16bit],目的端口[16bit],長度[16bit]、校驗和[16bit])。
稍安全
UDP沒有TCP擁有的各類機制,被攻擊利用的機制就少一些,可是也沒法避免被攻擊。
支持廣播單播組播
缺點不可靠
因爲UDP沒有TCP一系列的可靠性機制保證傳輸,在網絡質量很差時,很容易丟包。因此在使用UDP做爲通訊協議時,每每須要本身實現可靠性保證,例如確認重傳等。聽說QQ早期是使用UDP做爲通訊協議,本身在UDP的基礎上,實現相似TCP的可靠性保證,這樣一來,既可實現高速率的傳輸,又可兼顧可靠性。網上找到的一篇討論文:爲何QQ用的是UDP協議而不是TCP協議?[5],感興趣的能夠看看。
亂序
適用場景
對網絡通信質量要求不高、實時性要求較高的狀況下,可用UDP。好比:實時音視頻聊天,這種狀況丟一些幀影響不大,不須要重傳,對傳輸速度要求高。遙控器,丟一些指令不影響。


TCP簡單概述
TCP是一個面向字節流、面向鏈接的全雙工協議。通訊雙方在進行通訊以前,須要經過三次握手創建鏈接,確認雙方都具備數據收發的能力。因爲TCP是全雙工協議,所以在數據發送完畢後,每一個方向都須要單獨進行關閉,因此須要經過四次揮手來斷開TCP鏈接。另外,TCP提供了確認應答超時重傳滑動窗口流量控制慢啓動擁塞機制等機制來保證數據有序及可靠性。總的來講,TCP是一個可靠的協議
優勢可靠
TCP利用一系列機制保證數據傳輸的可靠性,好比確認應答超時重傳校驗和最大消息長度滑動窗口機制等。
有序
TCP協議在發送數據時,會對每一個分片作順序化,也就是會給每一個數據包分配一個序列號,而且在特定的時間內等待接收主機對分配的這個序列號進行確認,若是發送主機在一個特定時間內沒有收到接收主機的確認,則發送主機會重傳此數據包。接收主機利用序列號對接收的數據進行確認,以便檢測對方發送的數據是否有丟失或者亂序等,接收主機一旦收到已經順序化的數據,它就將這些數據按正確的順序重組成數據流並傳遞到高層進行處理。
缺點效率低
TCP因爲發送數據前經過三次握手創建鏈接,發送數據完成後須要經過四次揮手斷開鏈接,而且在發送數據過程當中,須要一系列機制來保證數據的可靠性以及順序性,因此相對於UDP來講,傳輸效率就低。
開銷大
TCP首部開銷爲最小20個字節(源端口[16bit]、目標端口[16bit]、序列號[32bit]、迴應序號[32bit]、TCP頭長度[4bit]、reserved[3bit]、控制代碼[6bit]、窗口大小[16bit]、偏移量[16bit]、校驗和[16bit]、選項[長度可變,最長可達40字節](可選))
適用場景
對網絡通信質量要求較高、傳輸效率要求相對低,要求數據準確無誤傳輸的場景。好比:金融類、社交App類等。 注:做者給你們找了幾篇很不錯的文章,有興趣的話能夠閱讀:1.網絡基礎:TCP協議-如何保證傳輸可靠性[6]2.TCP如何保證消息順序以及可靠性到達[7]3.深刻理解 TCP 協議:從原理到實戰[8]


WebSocket簡單概述
WebSocket是基於TCP實現的協議,自己就是TCP長鏈接應用的一種。不一樣的是,WebSocket握手採用Http請求,客戶端在鏈接服務器成功後,主動向服務端發起一個Http握手請求,服務端在收到握手請求並驗證經過後,給客戶端返回一個Response,至此,一個合法的長鏈接就創建了。握手完成後,日後發送數據就是經過TCP協議了,也就是說WebSocket只是使用Http協議來完成握手操做。總的來講,WebSocket是一個基於TCP實現並封裝的協議
優勢
因爲WebSocket是基於TCP實現的協議,因此優勢跟TCP基本相同。另外,遵循RFC規範的WebSocket標準實現,協議自帶包長,是不會產生粘包/拆包的狀況的,所以,甚至能夠認爲WebSocket的功能之一就是專門處理TCP粘包問題。固然,不必定全部的WebSocket實現都遵循RFC規範,因此極端的狀況,仍是得本身處理,能夠參考一下該答案的解釋:Websocket須要像TCP Socket那樣進行邏輯數據包的分包與合包嗎[9]。另外,WebSocket在TCP的基礎上,封裝了一些幀實現,方便咱們使用。  
缺點
同TCP。
適用場景
同TCP。另外,從WebSocket的命名能夠看出,比較適合Browser的即時通信實現。注:WebSocket和HTTP同樣都是基於TCP的應用層協議。握手部分的設計目的就是兼容現有的基於HTTP的服務端組件(web服務器軟件)或者中間件(代理服務器軟件)。這樣一個端口就能夠同時接受普通的HTTP請求或者WebSocket請求了。爲了這個目的,WebSocket客戶端的握手是一個 HTTP升級版的請求(HTTP Upgrade request)。感興趣能夠閱讀如下文章:

1.WebSocket(1) 簡單介紹及握手鍊接[10]


MQTT簡單概述
MQTT是一種基於發佈/訂閱模式的「輕量級」通訊協議,也是TCP長鏈接應用的一種(固然中間可能多一層WebSocket)。爲何既然有了TCP和WebSocket了,還須要有MQTT的存在呢?這是由於,MQTT有一個很大的優勢:能夠以極少的代碼和有限的帶寬,爲鏈接遠程設備提供實時可靠的消息服務,同時根據網絡環境不一樣,能夠選擇三種消息發佈的質量(QoS Level):1.QoS0,At most once,至多一次2.QoS1,At least once,至少一次3.QoS2,Exactly once,確保只有一次做爲一種低開銷、低帶寬佔用的即時通信協議,使其在物聯網、小型設備、移動應用等方面有較普遍的應用。在MQTT協議中,一個MQTT數據包由固定頭(Fixed header)、可變頭(Variable header)、消息體(payload)三部分構成:1.固定頭(Fixed header)。存在於全部MQTT數據包中,表示數據包類型及數據包的分組類標識。2.可變頭(Variable header)。存在於部分MQTT數據包中,數據包類型決定了可變頭是否存在及其具體內容。3.消息體(Payload)。存在於部分MQTT數據包中,表示客戶端收到的具體內容。總的來講,MQTT是在TCP之上的應用層協議,對物聯網應用環境作了很是多的優化,TCP傳輸層協議,是更通用層的協議
優勢
因爲MQTT是基於TCP實現的協議,因此優勢跟TCP基本相同。同時,MQTT也是標準的RFC協議,相比於私有協議而言更加標準,優勢有:1.協議很是完善,可以立刻用於生產。各端實現同一套協議以後,就能進行通訊;私有協議還須要進行大量的驗證,看有完好陷或欠考慮的地方。2.協議的標準化帶來大量的開源組件,下降開發難度。隨着物聯網+5G生態愈來愈好,開源組件愈來愈多,能夠減小重複編碼量。3.標準協議利於第三方接入。當第三方設備、平臺想要對接的時候,拿出一套標準的MQTT協議拍在他們臉上,再也沒人有理由要求改接口了。4.有不少開源的Broker,接入較方便等。固然,以上用TCP本身開發協議也能實現,那爲何須要MQTT呢?其實就是MQTT另外還實現了不少功能,下降了開發複雜度,好比:心跳機制、異步機制、遺囑消息、訂閱發佈機制,QoS消息質量等,並且MQTT作了一些優化,好比消息頭最小隻有兩個字節等。因此,能夠簡單理解爲,MQTT其實就是TCP協議的一種封裝實現,在TCP的基礎上作了一系列優化,而且封裝了不少實用的機制,一句話總結:MQTT就是觀察者模式的網絡放大版
缺點
同TCP。另外,雖然MQTT封裝了不少機制,但仍是不夠成熟,實現起來較複雜。
適用場景物聯網IoT即時通信IM嵌入式開發設備(不能常常聯網或網絡環境較差)推送車聯網平臺其它協議開銷較小的場景等注:感興趣可閱讀如下文章:1.一文讀懂MQTT協議[11]2.MQTT 入門介紹[12]3.MQTT相比於TCP長鏈接透傳的優點[13]

5


傳輸協議選型

經常使用的傳輸協議有如下幾種,分別講講每種傳輸協議的優缺點及使用場景。

JSON簡單概述
JSON是爲了數據交換設計的一種數據格式,採用key/value鍵值對存儲。相信你們平時在開發時已經有過許多接觸,就不展開介紹了。
優勢可讀性良好更加小巧,傳輸效率良好易解析缺點傳輸效率不算高(有須要冗餘的符號,好比":"、空格等)適用場景
絕大多數須要數據交互的場景,均可以使用。 

XML簡單概述
XML指可擴展標記語言,這裏也不做過多介紹。
優勢格式統一,符合標準可讀性較高、自我描述性高簡單、可擴展性高缺點體積龐大、無用的冗餘信息較多較難解析適用場景
配置文件、XMPP的通訊格式。 

Protobuf簡單概述
Protocol Buffers(簡稱Protobuf) ,是Google出品的序列化框架,與開發語言無關,和平臺無關,具備良好的可擴展性。Protobuf和全部的序列化框架同樣,均可以用於數據存儲、通信協議。Protobuf的序列化的結果體積要比XML、JSON小不少,XML和JSON的描述信息太多了,致使消息要大;此外Portobuf還使用了Varint編碼,減小數據對空間的佔用。Protobuf序列化和反序列化速度比XML、JSON快不少,是直接把對象和字節數組作轉換,而XML和JSON還須要構建成XML或者JSON對象結構。在一個須要大量的數據傳輸的場景中,若是數據量很大,那麼選擇protobuf能夠明顯的減小數據量,減小網絡IO,從而減小網絡傳輸所消耗的時間。考慮到做爲一個主打社交的產品,消息數據量會很是大,同時爲了節約流量,因此採用protobuf是一個不錯的選擇。
優勢傳輸效率快(序列化後體積較小)支持跨平臺多語言序列化/反序列化速度很快缺點可讀性較差(二進制格式)缺少自描述使用不太方便(貌似找不到支持原生c語言的protobuf,大都是通過別人編譯後的庫)適用場景
數據量大而且要求傳輸效率較高的場景。

6


通訊框架選型

經常使用的通訊框架有如下幾種,分別講講每種通訊框架的優缺點及使用場景。

Java Nio簡單概述
Java NIO 是 java 1.4, 以後新出的一套面向緩衝區、非阻塞的IO接口。既能夠說是New IO,也有人認爲是No-Blocking IO,但這種觀點不太嚴謹。NIO不只僅就是等於Non-blocking IO(非阻塞IO),NIO中有實現非阻塞IO的具體類,但不表明NIO就是Non-blocking IO(非阻塞IO)。Java NIO由如下幾個核心部分組成:1.Buffer 緩衝區2.Channel 通道3.Selector 多路複用器傳統的IO操做面向數據流,意味着每次從流中讀一個或多個字節,直至完成,數據沒有被緩存在任何地方。NIO操做面向緩衝區,數據從Channel讀取到Buffer緩衝區,隨後在Buffer中處理數據。NIO主要的事件有:1.OP_READ 讀就緒2.OP_WRITE 寫就緒3.OP_CONNECT 客戶端鏈接服務端事件4.OP_ACCEPT 服務端接收客戶端鏈接事件更多細節能夠查看官方文檔介紹。
優勢併發性高。相較於傳統的BIO(Blocking IO)的實現(一個鏈接佔用一個線程資源,而且線程資源得不到充分利用),NIO的Selector模型容許一個單獨的線程來監視多個輸入通道,也就是啓用了少許的線程(也許是單個線程)去對事件池作監控,對比BIO來講會節省不少cpu的資源,BIO是每一個鏈接創建一個線程,而且監控工做也是該線程完成,NIO將監控工做歸爲不多的線程去處理,固然這個線程不會再用於通訊,保證了每一個線程的利用率,天然提高了高併發性能。缺點API較複雜。必須對NIO的Buffer(緩衝區)、Channel(通道)、Selector(多路複用器)瞭解比較透徹才能開發出健壯的程序。須要不少額外的編程技能來輔助使用NIO,例如,由於NIO涉及了Reactor線程模型,因此必須必須對多線程和網絡編程很是熟悉才能寫出高質量的NIO程序。想要有高可靠性,工做量和難度都很是的大,由於服務端須要面臨客戶端頻繁的接入和斷開、網絡閃斷、半包讀寫、失敗緩存、網絡阻塞的問題,這些將嚴重影響咱們的可靠性,而使用原生NIO解決它們的難度至關大。JDK NIO中著名的BUG--epoll空輪詢,當select返回0時,會致使Selector空輪詢而致使CPU100%,官方表示JDK1.6以後修復了這個問題,其實只是發生的機率下降了,沒有根本上解決。適用場景
服務器須要支持超大量的長時間鏈接。好比10000個鏈接以上,而且每一個客戶端並不會頻繁地發送太多數據。例如總公司的一箇中心服務器須要收集全國便利店各個收銀機的交易信息,只須要少許線程按需處理維護的大量長期鏈接。Jetty、Mina、Netty、ZooKeeper等都是基於NIO方式實現。 

Mina簡單概述
Mina其實跟Netty很像,大部分API都相同,由於是同一個做者開發的。但感受Mina沒有Netty成熟,在使用Netty的過程當中,出了問題很輕易地能夠找到解決方案。在線程模型上,Mina和Netty並無太大的差別性,主要的差別仍是在任務調度的粒度的不一樣。另外,Mina是早期做品,Netty是在Mina以後開發的,同一個做者,功能大體的框架,因此Netty是一個不錯的選擇。
優勢
和Netty大體相同,只是某些實現上有所不一樣。
缺點Mina將內核和一些特性的聯繫過於緊密,使得用戶在不須要這些特性的時候沒法脫離,相比下性能會有所降低,Netty解決了這個設計問題。Netty的文檔更清晰,不少Mina的特性在Netty裏都有。Netty更新週期更短,新版本的發佈比較快。它們的架構差異不大,Mina靠apache生存,而Netty靠jboss,和jboss的結合度很是高,Netty有對google protocal buf的支持,有更完整的ioc容器支持(spring,guice,jbossmc和osgi)。Netty比Mina使用起來更簡單,Netty裏你能夠自定義的處理upstream events或/和downstream events,可使用decoder和encoder來解碼和編碼發送內容。Netty和Mina在處理UDP時有一些不一樣,Netty將UDP無鏈接的特性暴露出來;而Mina對UDP進行了高級層次的抽象,能夠把UDP當成」面向鏈接」的協議,而要Netty作到這一點比較困難。適用場景
同Netty。 

Netty簡單概述
Netty是由JBOSS提供的基於Java NIO的開源框架,Netty提供異步非阻塞、事件驅動、高性能、高可靠、高可定製性的網絡應用程序和工具,可用於開發服務端和客戶端。Netty是目前最流行的 NIO 框架,Netty 在互聯網領域、大數據分佈式計算領域、遊戲行業、通訊行業等得到了普遍的應用,知名的 Elasticsearch、Dubbo、阿里雲IoT框架內部都採用了 Netty。
優勢設計優雅。適用於各類傳輸類型的統一 API 阻塞和非阻塞 Socket;基於靈活且可擴展的事件模型,能夠清晰地分離關注點;高度可定製的線程模型 - 單線程,一個或多個線程池。使用方便。詳細記錄的 Javadoc,用戶指南和示例;沒有其餘依賴項,JDK 5(Netty 3.x)或 6(Netty 4.x)就足夠了。高性能。吞吐量更高、延遲更低、減小資源消耗、最小化沒必要要的內存複製。安全。完整的 SSL/TLS 和 StartTLS 支持社區活躍。不斷更新、版本迭代週期短,發現的 Bug 能夠被及時修復,同時更多的新功能會被加入。高穩定性。解決了JDK NIO臭名昭著的epoll空輪詢bug。定製能力高。能夠經過ChannelHandler對通訊框架進行靈活地拓展。支持各類協議。好比TCP、UDP、WebSocket、MQTT等,高度封裝的編解碼器,簡單易用。經歷了大規模的商業應用考驗,質量和可靠性都有很好的驗證。缺點
暫未發現,有知道的能夠告訴做者,謝謝。
適用場景互聯網行業。在分佈式系統中, 各個節點之間須要遠程服務調用, 高性能的 RPC 框架必不可少, Netty 做爲異步高性能的通訊框架, 每每做爲基礎通訊組件被這些 RPC 框架使用。遊戲行業。Netty 做爲高性能的基礎通訊組件, 提供了 TCP/UDP 和 HTTP 協議棧, 方便定製和開發私有協議棧, 帳號登陸服務器;地圖服務器之間能夠方便的經過 Netty 進行高性能的通訊。Netty除了能開發即時通信類的應用外,也能用來實現HTTP服務器。


Socket.IO
Socket.IO也是一個開源框架,可用於在瀏覽器和服務器之間進行實時,雙向和基於事件的通訊。用得比較少,就不詳細介紹了。

7


通用協議定義

主要是講講Protobuf的文件格式定義,JSON就是key/value鍵值對,沒什麼好說的。
咱們先分析一下,怎樣的消息格式,纔算是通用的,也就是單聊、羣聊、系統消息等,均可以用的統一消息格式,這個比較重要,關係到後續的擴展性、通用性等,先看個圖:

Protobuf格式定義



對應編寫的msg.proto代碼以下:

 1syntax = "proto3";// 指定protobuf版本
2option java_package = "com.freddy.kulaims.protobuf";// 指定包名
3option java_outer_classname = "MessageProtobuf";// 指定類名
4
5message Msg {
6    Head head = 1;// 消息頭
7    Body body = 2;// 消息體
8}
9
10message Head {
11    string msgId = 1;// 消息id
12    int32 msgType = 2;// 消息類型
13    string sender = 3;// 發送者
14    string receiver = 4;// 接收者
15    int64 timestamp = 5;// 發送時間戳,單位:毫秒
16    int32 report = 6;// 消息發送狀態報告
17}
18
19message Body {
20    string content = 1;// 消息內容
21    int32 contentType = 2;// 消息內容類型
22    string data = 3;// 擴展字段,以key/value形式存儲的json字符串
23}

編寫完msg.proto文件後,經過如下步驟便可生成咱們須要用到的MessageProtobufJava類:

1.在項目src/main目錄下,新建proto文件夾,與src/main/java同級。2.msg.proto文件複製到項目src/main/proto文件夾。3.project級的build.gradle文件的dependencies節點下,加入

1classpath 'com.google.protobuf:protobuf-gradle-plugin:0.8.12'

   4.app級的build.gradle文件,加入

1apply plugin: 'com.google.protobuf'

   5.app級的build.gradle文件的android節點,加入

 1sourceSets {
2    main {
3        java {
4            srcDir 'src/main/java'
5        }
6
7        proto {
8            srcDir 'src/main/proto'
9        }
10    }
11}


   6.app級的build.gradle文件的dependencies節點,加入

1implementation 'com.google.protobuf:protobuf-java:3.8.0'


   7.app級的build.gradle文件根節點(也就是與androiddependencies節點同級),加入

 1protobuf {
2    //配置protoc編譯器
3    protoc {
4        artifact = 'com.google.protobuf:protoc:3.8.0'
5    }
6    //這裏配置生成目錄,編譯後會在build的目錄下生成對應的java文件
7    generateProtoTasks {
8        all().each { task ->
9            task.builtins {
10                remove java
11            }
12            task.builtins {
13                java {}
14            }
15        }
16    }
17}


   8.點擊build->Make Project,便可在項目生成的build/generated/source/proto/debug/java/proto文件java_package指定的包名下看到生成的MessageProtobuf.java文件,文件自動生成,不須要改動:

生成的MessageProtobuf文件

注:以上protobuf版本不是規定的,你們能夠選擇本身喜歡的版本,但強烈建議先後端版本一致,不然有可能會出現兼容性的問題。

很多同窗也會用多個proto文件來表示不一樣消息,好比用戶登陸消息user_login.proto、聊天消息chat.proto,這樣也何嘗不可,只是這樣會有不少個proto文件,後期維護比較麻煩,這也就是爲何須要設計通用的proto文件格式的緣由。

最後,貼一張JSONProtobuf序列化後的字節長度對比圖,兩個User對象和一個timestamp字段,能夠看到json序列化後,字節長度爲140,而一樣的內容在Protobuf序列化後,字節長度爲49

JSON與Protobuf序列化字節長度對比


拿到MessageProtobuf.java文件,意味着咱們已經完成了第一步,距離咱們開發完成的商業級IM系統又接近了一步,在下一篇文章,我將會詳細介紹接口定義及封裝,敬請期待。



8


最終技術選型

綜上所述,在即時通信方面,最終技術選型以下:

通訊協議

通訊協議採用TCPWebSocket兩種,UDP不考慮,至於MQTT,後續若是有須要的話會考慮實現。

傳輸協議

傳輸協議採用ProtobufJSON兩種,在IM SDK初始化時指定。XML不考慮。

通訊框架

通訊框架採用Netty,後續若是有須要,會採用Java NIOMina實現。Socket.IO不考慮。


9


寫在最後

以前在開源一個自用的Android IM庫,基於Netty+TCP+Protobuf實現[14],有同窗評論,TCP是面向字節流的,沒有包的概念,哪來的拆包/粘包的說法呢?首先說明,做者不會誤導你們,TCP確實沒有拆包/粘包的說法,相關的TCP/IP書籍上也沒有提到過,這個說法只是誤傳,但已經深刻人心,因此做者也就用這詞了。拆包/粘包的概念應只存在應用層,TCP不存在粘包/拆包的說法,只是沒有消息邊界而已。後續在第3篇文章,會專門解釋。

終於寫完了,發現寫原創文章太難了,一來要考慮表述的方式,二來要考慮排版是否美觀,還要考慮是否符合你們的須要,因此拖延症又發做了~ 但會堅持把整個系列的文章都寫完,把項目完善並開源,但願對你們有所幫助。之因此分系列文章來寫,一方面是由於一篇文章實在沒辦法講清楚。另外一方面,但願在寫文章的過程當中,你們能夠給我提點意見或建議。一我的精力及水平有限,有不少觀點也許不太正確和完善,但願你們體諒。歡迎吐槽,歡迎拍磚,接受批評。

PS:新開的公衆號不能留言,若是你們有不一樣的意見或建議,能夠到掘金上評論或者加到QQ羣:1015178804,若是羣滿人的話,也能夠在公衆號給我私信,謝謝。

The end.

References

[1] NettyChat: https://github.com/FreddyChen/NettyChat
[2] 開源一個自用的Android IM庫,基於Netty+TCP+Protobuf實現: https://juejin.im/post/5c97ae12e51d45580b681b0b
[3] Github: https://github.com/FreddyChen
[4] 開源一個自用的Android IM庫,基於Netty+TCP+Protobuf實現: https://juejin.im/post/5c97ae12e51d45580b681b0b
[5] 爲何QQ用的是UDP協議而不是TCP協議?: http://www.52im.net/forum.php?mod=viewthread&tid=279&page=1#pid1092
[6] 網絡基礎:TCP協議-如何保證傳輸可靠性: https://blog.csdn.net/liuchenxia8/article/details/80428157
[7] TCP如何保證消息順序以及可靠性到達: https://blog.csdn.net/dccmxj/article/details/52103800?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-2.edu_weight&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-2.edu_weight
[8] 深刻理解 TCP 協議:從原理到實戰: https://juejin.im/book/5c70dbbe51882562046911bc
[9] Websocket須要像TCP Socket那樣進行邏輯數據包的分包與合包嗎: https://wenwen.sogou.com/z/q713107248.htm
[10] WebSocket(1) 簡單介紹及握手鍊接: https://www.jianshu.com/p/8414d2efa087
[11] 一文讀懂MQTT協議: https://www.jianshu.com/p/5c42cb0ed1e9
[12] MQTT 入門介紹: https://www.runoob.com/w3cnote/mqtt-intro.html
[13] MQTT相比於TCP長鏈接透傳的優點: https://www.cnblogs.com/alix-1988/p/13159369.html
[14] 開源一個自用的Android IM庫,基於Netty+TCP+Protobuf實現: https://juejin.im/post/5c97ae12e51d45580b681b0b


本文分享自微信公衆號 - FreddyChen(FreddyChenAndroid)。
若有侵權,請聯繫 support@oschina.cn 刪除。
本文參與「OSC源創計劃」,歡迎正在閱讀的你也加入,一塊兒分享。

相關文章
相關標籤/搜索