Original:http://blog.csdn.net/phunxm/article/details/5086080編程
在OSI開放互聯參考模型中,對等實體(peer)之間數據單元在發送方逐層封裝(encapsulation),在接收方的逐層解析(decapsulation)。發送方N層實體從N+1層實體獲得的數據包稱爲服務數據單元(Service Data Unit,SDU)。N層實體只將其視爲須要本實體提供服務的數據,將服務數據單元進行封裝,使其成爲一個對方可以理解的數據單元(Protocol Data Unit,PDU),封裝過程其實是爲SDU增長對等實體間約定的控制信息(Protocol Control Information,PCI)的過程。服務器
爲了保證網絡的各個功能的相對獨立性,以及便於實現和維護,一般將協議劃分爲多個子協議,而且讓這些協議保持一種層次結構,子協議的集合一般稱爲協議簇(Protocol Family)。網絡
網絡協議的分層有利於將複雜的問題分解成多個簡單的問題,從而分而治之。各層的協議由各層的實體(entity)實現,通訊雙方對等層中完成相同協議功能的實體稱爲對等實體。對等實體按協議進行通訊,因此協議反映的是對等層的對等實體之間的一種橫向關係,嚴格地說,協議是對等實體共同遵照的規則和約定的集合。架構
通訊協議精確地定義了雙方通訊控制信息和解釋信息:發送方能將特定信息(文本、圖片、音頻、視頻)按協議封裝成指定格式的數據包,最終以串行化比特流在網絡上傳輸;接收方接收到數據包後,根據協議將比特流解析爲本地化數據,從而獲取對方發送過來的原始信息。編程語言
通訊協議包括三個要素:分佈式
(1)語法:規定了信息的結構和格式;函數
(2)語義:代表信息要表達的內容;性能
(3)同步:規則涉及雙方的交互關係和事件順序。測試
整個計算機網絡的實現體現爲協議的實現,TCP/IP協議是Internet互聯網的核心協議。大數據
(1) 協議的開發主要包括協議設計、協議形式描述、協議實現和協議一致性測試。協議的開發過程與步驟如圖1所示。
圖1 協議開發過程與步驟
(2) 協議設計過程當中的分組發送接收模型如圖2所示。
圖2協議設計過程當中的分組發送接收模型
(3)協議的一致性測試
協議的一致性測試是指測試協議可否按照預想的控制策略實現正確的通訊,主要體如今數據包經過信道從信源傳送到信宿後,信宿可以根據協議正確的解析出原始信息。
協議的一致性測試如圖3所示。
圖3 協議一致性測試環境
根據測試環境的能夠分爲局部測試和分佈式測試,如圖4所示。
圖4局部測試法、分佈式測試法
爲方便描述自定義協議,仍是借用數據包和數據報來描述封裝數據單元和傳輸數據單元,但這裏的數據包和數據報徹底不一樣於TCP/IP架構中的Packet和Datagram概念。
下文所述的數據包指封裝的基本單位,以TLV(Type-Length-Value)格式封裝基本消息單位;數據報Package是傳輸的基本單位,頭部包含序列號和命令信息。接收端根據命令信息分辨事件類型,作出不一樣的解析。報文實體是多個TLV數據包組成的鏈表。
從應用層HTTP協議,到超文本置標語言HTML(HyperText Mark-up Language),再到可擴展置標語言XML(Extensible Markup Language),它們提供了數據的格式化存儲、傳輸和格式化顯示的規範,是網絡通訊的基石。然而HTTP協議以及HTML/XML置標語言的本質就是定義一堆標籤(Tag)對數據進行串行化序列化,而後接收方再根據標籤解析、還原數據。
自定義通訊協議的關鍵是對數據包的合理構造(construct)和正確解析(parse),即制定編解碼規則。
抽象語法標記ASN(Abstract Syntax Notation) BER的長度肯定的編碼方式,由3部分組成Identifier octets、Length octets和Contents octets,實際上這就是一種TLV(Type-Length-Value)模型:類型字段(Type或Tag)是關於標籤和編碼格式的信息;長度字段(Length)定義數值的長度; 內容字段(Value)表示實際的數值。
所以,一個編碼值又稱TLV三元組。編碼能夠是基本型或結構型,若是它表示一個簡單類型的、完整的顯式值,那麼編碼就是基本型(primitive);若是它表示的值具備嵌套結構,那麼編碼就是結構型 (constructed)。
TLV編碼就是指對Type(Tag)、Length和Value進行編碼,造成比特流;解碼是編碼的逆過程,是從比特流緩衝區中解析還原出原始數據。
採用C++編程語言設計TLV協議類,其類視圖如圖5所示。
圖5 CTLV類視圖
目前只提供設置整形值(int型)的setValue_Int和設置字符串值(C_String型)的SetValue_Cstring兩個接口。
TLV將數據封裝成包的格式如表1所示。
TLV包 |
||
頭部 |
包實體 |
|
m_dwTag |
m_nLen |
m_pValue |
表1 TLV包格式
TLV的接口說明:
(1)值類型標籤m_vtTag是內部輔助枚舉變量,它根據構造TLV時傳遞的服務類型標籤m_dwTag來肯定。
(2)TLV::m_nLen在爲TLV設置具體值時肯定。
(3)TLV包的封裝:
(4)TLV包的解析:建立一個TLV對象後,調用TLV::fromBuffer方法從緩衝區streamBuffer解析出TLV。
(5)封裝和解析涉及到本機字節順序和網絡字節順序的轉換問題。
(6)調用TLV::setValue_*方法填充TLV時,統一字節邊界數爲4。
不一樣於底層的數據包/數據報只是對數據層次的封裝解析,實際應用程序是以事件驅動的,所以必須註冊不一樣的信令(事件類型標籤),而後填充到數據報中。接收端根據信令作出相應的事件處理。
例如在C/S通訊系統中,客戶端每每要先登陸,經過服務器端的校驗才能進行後續通訊。所以客戶端運行後,須要構造並向服務器端發送含有LOGIN信令的包含用戶名字符串strUserName和密碼字符串strPassWord的數據報;服務器端解析LOGIN信令後作校驗處理,而後發送含有LOGIN_RESPONSE信令和校驗結果的回執數據報給客戶端。
採用C++編程語言設計Package類,其類視圖如圖6所示。
圖6 CPackage類視圖
Package類將TLV封裝成包的格式如表2所示。
Package包 |
||||
頭部 |
序列號 |
包實體 |
||
m_nCmdLen |
m_dwCmdID |
m_dwCmdState |
m_nSeqNo |
Count*TLV |
表2 Package包格式
Package的接口說明:
(1)Package::m_nCmdLen是整個Package包的長度,將其做爲首個字段的好處在於當傳送大數據包時,接收方能夠根據數據長度來控制讀狀態,從而將一個大數據包分批接收。
(2)Package::m_nCmdLen在構造函數中初始化爲16,在調用Package::addTLV方法填充包實體時增加。
(3)Package包的封裝:
(4)Package包的解析:
(5)Package::toBuffer方法和Package::fromBuffer方法主要遍歷Package::m_TLV_List列表,而後調用TLV::toBuffer方法和TLV::fromBuffer方法解析出TLV數據單元。
TLV數據包的功能測試(主要是本地測試)
鑑於實際通訊數據最後都要轉換成比特流,故只測試發送字符串類型的變量,僅測試協議可否正確打包、解析。其餘類型的普通數據均可以轉換成字符串傳輸,最後,接收方根據m_dwTag肯定值類型m_vtTag,解析出具體值。
對TLV::setValue_C_String方法填充TLV的測試,須要考慮字節對齊問題。對於長度爲4字節倍數的C狀態字符串,打包時省去末尾的‘/0’結束標誌符。須要測試長度非4倍數的字符串和長度爲4倍數的字符串。
經本地測試,調用TLV::setValue_Int方法和TLV::setValue_C_String方法構造整形和字符串時,可以正確封裝、正確解析。
Package數據報的功能測試,主要是將TLV組合成包,而後添加信令,完成特定的通訊。對登錄LOGIN和發送消息SUBMIT_SM的測試代表Package協議能正確封裝、正確解析。
在實際項目中使用Package通訊協議,對於稍大一點的數據塊須要控制好讀的步驟,以便能接收整包完整的信息。
本文示例代碼下載:《TLV應用層協議開發示例》
參考:
《計算機網絡協議和實現技術》 魯士文