客戶端架構設計的簡單總結(轉)

from:http://www.cppblog.com/weiym/archive/2014/07/26/207819.html

咱們知道,客戶端是相對服務端而言的,客戶端程序相對普通應用程序,主要是增長了網絡通信功能。在這個移動和雲存儲的年代,大部分終端應用程序都有網絡通信功能, 因此均可以稱爲客戶端。常見的客戶端如瀏覽器,IM客戶端, 網絡會議客戶端,郵件客戶端,微博和微信客戶端等...

經過觀察,咱們會發現全部的客戶端基本是大同小異,都會包括一些相同的功能組件, 下面簡單例舉下:
javascript

 
通信協議層
 
既然客戶端都有網絡功能,就會涉及到通信方式和數據格式以及協議, 這三者不是徹底獨立,而是有機統一的。

首先說通信方式,常見的通信方式包括TCP,UDP, P2P和http(s), 不少時候咱們不會用單一的通信方式,而是多種通信方式的結合。好比說TCP端口被封,走不通時,咱們會轉成嘗試http(s)。IM中聊天文本走的是TCP, 由服務器轉發,可是2個客戶端之間的文件傳輸咱們可能走的又是P2P了, 多我的之間的語音聊天, 咱們走的又是UDP了。

其次說數據格式,常見的數據格式包括二進制編碼,開源序列化協議和文本格式。
二進制通常是自定義的私有格式,一般對數值,咱們會轉成大頭端,對字符串咱們會用UTF8 編碼,由於沒有冗餘數據,它的優勢是不會浪費帶寬;主要缺點是有硬編碼的味道,很差擴充。
開源序列化協議這裏主要是指google的protocal buffer,  如今不少公司都在用, 不少人基於它開發了本身的RPC框架。主要優勢是數據小,使用簡單而高效。
文本格式主要是指xml和json. 相對來講xml比較清晰和容易擴充,可是冗餘數據比較多。json藉助javascript對它語言層次的支持,感受主要是前端人員使用的比較多。

最後再說協議,  協議和咱們的應用相關聯。好比郵件客戶端,固然是走SMTP和POP3了; IM客戶端的話,通常走XMPP了;  網絡會議的話,能夠走ITU的T.120協議, 也能夠RFC 6501定義的XCON, 信令走SIP, 數據走RTP等。

通訊協議層是整個客戶端網絡事件驅動的引擎,它可能會比較簡單,也可能會很複雜。若是是基於XMPP的IM, 它可能會比較簡單,由於基本上只須要一層文本協議的封包和解包就能夠了。 當若是是基於T.120網絡會議客戶端,就會比較複雜,它數據包走的自定義的二機制格式,按照T.120協議的建議, 在通信協議層又分了3層:TP, MCS和GCC。TP層主要封裝數據傳輸的方式, 可讓上層無差異的區分TCP和http(s)。 MCS層主要提供多點傳輸功能, 它抽象出通道(channel)這個概念, 讓不一樣session的數據進行邏輯隔離, 上層用戶能夠同時加入不一樣的通道來進行一對一和一對多的數據收發,而且通道中的數據有不一樣的優先級, 還有令牌這個機制。咱們也能夠在MCS層對數據進行加密和壓縮, 還能夠對上層的大數據包進行切包等。 GCC層主要封裝會議的最基本邏輯,好比建立會議和加入session數據包的格式封裝等, 讓上層能夠經過API調用而不用關心協議要求的數據包格式。不一樣的數據包會工做在不一樣的層次, 好比心跳包可能在底層TP層就被攔截了,它不要再往上層發,由於上面不用關心這個; 而有些數據包,則須要從底層往上層按照整個協議棧層層轉發,固然每層都會剝離掉本身的協議頭, 直至上層用戶數據到達它的最終用戶。

總之,通信協議層封裝了客戶端和服務端的通信方式及協議格式, 讓上層用戶不用關心底層的通訊機制, 而只關注應用的接口事件。理論上咱們能夠在上層應用不作大調整的前提下,直接將網絡會議客戶端中的T.120協議成基於SIP的XCON。
 
功能組件
 
一個客戶端程序一般是由不少功能模塊組成,模塊按功能來講能夠分爲基礎組件和應用組件。

基礎組件爲應用組件提供的基礎設施,基礎組件是能夠在不一樣的項目中重複使用的(好比界面控件庫,2D渲染引擎Skia, 跨平臺的網絡和線程庫等)。 
應用組件一般和咱們當前的特定應用程序相關,好比咱們的網絡會議客戶端包含的桌面共享模塊, 文檔共享模塊,視頻音頻模塊,文本聊天模塊等。

應用模塊自己分爲帶界面和無界面兩種狀況, 帶界面的狀況下咱們一般會給組件提供一個容器窗口的句柄, 讓組件本身在內部組織本身的界面。這種帶界面的組件一般會爲邏輯和界面的分離帶來麻煩,在Window上實現一些半透明和動畫效果也很難。 好比咱們想提供跨平臺的SDK來封裝邏輯,這時咱們會更傾向讓應用組件採用無界面的模式,組件在跨平臺層只封裝邏輯和提供數據, 而把數據發到最上層界面層後再統一處理。

對功能組件咱們的設計原則是儘可能保持獨立和可複用,最好能以仿COM方式動態升級而不用從新編譯, 另外組件之間要保持層次性,避免雙向或是循環依賴。
 
數據存儲
 
客戶端自己是處理和收發網絡數據, 這裏就涉及到對這些數據如何組織和存儲的問題。這個一般會根據客戶端的類型採用不一樣的到處理方式:
對於永久存儲的數據,固然是保存成文件或是存入數據庫,文件如xml, 數據庫如ACCESS,  SQL server, mysql等。
臨時數據固然是存入內存了,根據須要採用不一樣的數據結構, 組織格式如array,list, map, hashmap等。
還有一種是常見的數據保存方式是內存數據庫,最多見是SQLite了, 內存數據庫既能高效的分類保存大量數據, 又能夠直接用基於SQL語句進行查詢和處理, 好比foxmail客戶端就是用SQLite存儲的郵件信息。
還有一種是跨進程共享的數據,咱們通常固然是內存映射文件了。好比咱們有一個實時顯示log的工具, 咱們一般會在對方應用程序裏分配共享內存的內存映射文件,全部的log都寫到裏面,而後在log工具程序裏讀取和顯示。
固然還有一些數據可能存到網上去的, 常見的好比咱們的雲筆記, 這時數據分服務端數據和本地cache。

對於數據存儲咱們的設計原則是根據須要,選擇簡單高效的方式。好比咱們在設計網絡會議客戶端時曾討論要不要引入SQLite, 理想狀況是引入內存數據庫後各個組件和上層應用的數據均可以統一存儲,採用數據驅動的方式,能夠很方便的跟蹤整個客戶端的運行狀況。但後來發現這種設計會把原本各自獨立的組件經過數據庫耦合在了一塊兒,並且各組件的數據格式自己都很不要同樣, 很難統一存儲, 另外不少數據實際也只是臨時數據, 不必把簡單的時間作複雜了。
 
 
客戶端框架
 
客戶端框架通常有兩個做用:一是把全部的功能組件組織起來,進行統一的管理和展示; 二是實現整個客戶端的主界面。客戶端框架在協調各個組件時, 要注意避免讓組件之間產生雙向依賴, 而是應該讓組件把事件通知給框架後由框架統一協調和處理, 因此客戶端框架一般是整個客戶端邏輯最複雜的部分。 一個好的客戶端框架,一般會採用插件方式設計,能夠動態插拔鬚要的組件。最好是能夠根據服務端的配置, 動態下載和更新所須要的插件。

對於客戶端框架, 咱們的設計原則是低耦合和可擴展。基本上全部下層組件的改動都會影響到咱們的客戶端框架,客戶的不少新需求和新組件也會致使框架產生壞味道, 這裏咱們設計時就要考慮如何讓客戶端框架能及時的適應這些變化。
 
 
界面庫

客戶端確定會有界面,在Windows平臺上,如今的界面大體分爲如下幾類:
基於Windows原始窗口控件句柄的C++ native 客戶端, 基於.net的winform客戶端,基於.net的WPF客戶端,基於C++的DirectUI客戶端, 以嵌入瀏覽器(如webkit)方式實現的客戶端, 還有一類是基於Xaml的Metro客戶端。

對於企業級大型安裝應用,主要考慮的是開發效率,因此客戶端仍是以.net爲主; 可是對於互聯網企業, 更多的是要求客戶端精簡而高效, 因此仍是以C++爲主。 這裏就設及到C++的兩種界面庫, 一種是基於windows窗口句柄和控件自繪機制的界面庫,還有一中是基於DirectUI的界面庫, 如今大一點的公司基本上都有本身的DirectUI界面庫。基於修改Webkit方式實現的界面庫能夠經過Canvas和SVG動畫等方式實現一些很炫的效果, 可是它和標準程序的用戶體驗仍是有必定差距:一來web實現的控件跟Windows標準控件有很大不一樣, 二來web的流式佈局和應用程序的網格佈局也不同。

對於界面,我的以爲這個東西變化實在太快了,因此我以爲應該儘可能用界面和邏輯相分離的方式組織代碼。
 
總結
對於客戶端架構設計,我的以爲最大的原則就分層設計, 每層都封裝一個概念並保持獨立, 同時根據依賴倒置的原則, 站在上層客戶的角度提供接口。軟件工程裏面的一條黃金定律:「任何問題均可以經過增長一個間接層來解決。
相關文章
相關標籤/搜索