原文:http://blog.sina.com.cn/s/blog_6203dcd60100y2gd.htmlhtml
【第十二階段 :傳輸協議、接口、遠程調用】編程
這一部分主要談談關於協議、接口和遠程調用相關的內容。原本這一部分應該在以前就有比較詳細的討論,不過我放到後面來,足見其重要性。特別是在系統愈來愈多的時候,這幾個東東直接決定了咱們的開發速度和運維成本。服務器
好,接下來咱們一個個的看。網絡
1、傳輸協議負載均衡
到目前爲止,在不一樣系統之間獲取數據的時候,你是採用那種方式呢?框架
咱們簡單看一個例子:運維
以上這個多是咱們最(|兩萬字的分隔線|)初學習網絡編程的時候,最常使用的一種C-S交互方式。其實這裏面咱們已經定義了一種交互協議,只是這種方式顯得比較山寨,沒有規範。擴充性等等都沒有充分考慮。異步
咱們在學習網絡編程的時候,老師就給咱們講過,網絡分層的概念,經典的有5層和7層模型。在每一層裏面,都有本身的協議。好比:IP協議、TCP協議、HTTP協議等等。這些協議基本上都由兩部分組成:頭+數據。函數
【頭信息】工具
咱們來看看TCP協議:
(注:以上是我從百度百科上截取的)
頭信息中,通常可能會包含幾個重要的元素:協議標識符、版本號、串號(或是本次交互的id)、數據包長度、數據校驗等信息,可能有些協議還會帶一些其餘數據,好比數據發出方名稱、接收方名稱、時間、保留字段等等信息。
這些信息的目的,就是爲了清晰的表達,我是怎麼樣的一個協議,我有哪些特徵,我帶的數據有多大。方便接收方可以清晰的辨認出來。
【數據部分】
數據部分是爲了讓應用層更好的通信和表達數據。要達到的目標就是簡潔高效、清晰明瞭。提及來很容易,可是實現起來要考慮的東西就比較多,好比:數據壓縮、字符轉移、二進制數據表達等等。
咱們一般有多種格式來做爲數據部分的協議。大致上能夠分爲:
A、二進制流。好比:C裏面的結構體、JAVA裏面的Serializable,以及像Google的protobuf等。將內存裏面實體的數據,按字節序列化到緩衝區。這種方式的好處就是數據很是緊湊,幾乎沒有什麼浪費。可是,問題也比較明顯。雙方必須很清楚協議,面向的語言基本上是要求同樣的,很難作兼容,跨平臺差。且擴展性比較差。另外,還有網絡大小端字節序(Big-Endian、Little-Endian)的問題須要考慮。
B、文本傳輸協議。就是以字符串的方式來組織信息。常見的有XML、JSON等等。這種方式的好處就是擴展性強,跨平臺兼容能力好,接口標準且規範。問題就是傳輸量比較大,須要考慮作壓縮或者優化。
XML方式:
JSON方式:
所以,咱們能夠按照咱們實際的需求,來定製咱們想要的數據格式,從而達到高效和易於表達和擴展的效果。
通過上述分析,咱們基本上對傳輸協議有了一個比較大體的瞭解。有了傳輸協議以後,咱們的跨機器間的數據交互,才顯得比較規範和具備擴展性。若是咱們還不想本身來定義協議,咱們能夠用現有的協議進行組合,好比:HTTP+XML、HTTPS+JSON等等。只要在一個平臺上,你們都遵照這樣的規範,後續開發起來就變得輕鬆容易。
2、接口(或者API)
接口是咱們的服務對外表達的窗口。接口的好壞直接決定了咱們服務的可表達性。所以,接口是一個承上啓下的做用。對外,很好的表達提供的服務名稱、參數、功能、返回的數據等;對內,可以自動生成描述所對應的代碼函數框架,讓開發者編寫實現。
咱們描述咱們接口的方式有不少,能夠利用描述性語言來表達。好比:XML、JAVA裏提供的IDL(Interface Definition Language)等等。咱們把這種描述接口的語言統一稱爲IDL(Interface Definition Language)。
咱們能夠本身開發一些工具,將IDL進行翻譯,轉換成方便閱讀的HTML格式、DOC、CHM等等。方便其餘開發者查閱。
同時,另一方面,咱們能夠將IDL轉換成咱們的接口代碼,讓服務接口的開發者和調用方的開發者按規範和標準來實現。
對於下層代碼如何來實現數據的解析、函數的調用、參數的傳遞、數據的轉換和壓縮、數據的交換等等工做,則由工具來生成。對上徹底屏蔽。詳細的內容,咱們將在接下來的遠程調用中來分析。
3、遠程調用
咱們最初寫代碼的時候,就被教授了函數的概念。咱們能夠將一些公用的代碼,或者實現必定含義或邏輯的代碼,作成一個函數,方便重複的使用。
最開始,這些函數每每在同一個文件裏,咱們只要先申明,便可使用。
後來,咱們開始使用庫裏面的函數,或是將函數封裝成一個個的庫(好比C裏面的靜態庫.a或者動態庫.so,或者是Java裏面的.jar)。
以上對於函數的調用,以及函數自身的處理都是在本地。假如,當咱們單機不能知足需求的時候,咱們就須要將函數的處理放到其餘機器上,讓機器作到並行的計算。這個時候,咱們就須要遠程的函數調用,或者叫作遠程過程調用(Remote Procedure Call 或者 Remote Method Invoke,簡稱RPC或者RMI)。
咱們在這以前講過幾個東東:負載均衡、命名位置服務、協議、接口。其實前面講這幾個東東都是爲了給遠程過程調用作鋪墊。RPC都是創建在以上部分的基礎上。
仍是按照咱們以前分析問題的思路:爲何要這個東東?這個東西解決什麼問題?如何實現?有哪些問題?等等來分析RPC吧。
RPC的目的,就是使得從不一樣服務上獲取數據如同本地調用同樣方便和天然。讓程序調用者不須要了解網絡細節,不用瞭解協議細節,不用瞭解服務的機器狀態細節等等。若是沒有RPC,其實也是能夠的,就是咱們寫程序的時候難受點而已,哈哈。
接下來,咱們看看如何來實現。
以上是整個的一個大致靜態邏輯。最早編寫調用的IDL,完成後由工具生成接口說明文檔(doc);同時,生成客戶端調用代碼(stub,咱們叫作存根);另外,須要生成server端接口框架(skeleton),接口開發者實現具體的代碼邏輯。
以上就是客戶端調用的整個邏輯。
(今天先寫到這裏,明天要上班,須要早睡。PS:泰坦尼克3D還真不錯,我以爲主要緣由不是由於3D效果,而是重溫沒法超越的經典!)
(好,繼續昨天的話題。)
客戶端的使用很是簡單,利用工具生成的庫或者代碼(推薦是庫的方式,便於維護和升級),編譯進代碼或者運行時動態加載均可以。調用時直接使用函數調用方式便可。
而在庫裏,整個流程如上圖:
A、先根據服務名稱,從命名位置服務上獲取服務信息,包括機器列表、端口、協議類型等等;
B、而後將傳入參數和調用函數等信息按協議打包;
C、以後利用鏈接池和負載均衡策略,從中選取可用的鏈接,發送數據給服務器。
D、這個時候,若是咱們使用的是同步模式,咱們就等待數據返回。若是是異步模式,就直接先返回,等有數據回來後,再調用回調函數。
E、當數據回來後,咱們將數據按協議解包,並拼裝成對應的類或結構體,返回給調用者。
整個客戶端的調用過程對調用者是透明的,看起來就跟本地調用同樣。調用者不用關心個人機器在哪裏,用的哪一個端口,用的什麼協議,數據應該怎麼組裝等等。全部的一切,都已經作好,看起來是那麼的完美和簡單!
再來看看server端的流程。
server端的處理邏輯就比較簡單,跟據參數來分發不一樣的請求,處理完成後,就打包返回數據便可。開發者要實現的就是紅色部分。其餘均有代碼框架生成。
好了,咱們再回過頭來看看,整個遠程過程調用,
目標:讓系統間的耦合儘量降到最低;簡化開發,提高開發效率。
方法:利用了命名位置服務、負載均衡、網絡交互協議、程序交互接口等工具
效果:使得開發遠程數據獲取和本地調用同樣簡單有效,不用關係底層細節。
固然,在咱們實際作的過程當中可能會遇到不少問題,好比:如何考慮跨平臺的實現?如何考慮擴展性?如何來管理鏈接池等等。不過這些問題只要考慮到了,都是能夠解決的。
在業界,其實也有不少成熟的系統,好比Microsoft的COM/DCOM、OMG的CORBA、SUN的EJB等等。因此遠程過程調用其實都是比較成熟和現成的東東。不過要把他作好,真的是不容易,要考慮的東西太多。若是真能作好,整個系統就完美了!