1. 程式人生 > 其它 >應用層/安全層/傳輸層如何進行協議選型?

應用層/安全層/傳輸層如何進行協議選型?

系統設計,協議先行。

大部分技術人沒有接觸協議的設計細節,更多的是使用已有協議進行應用層的編碼,例如:

(1)使用http作為載體,設計get/post/cookie引數

(2)使用dubbo框架,而不用去深究內部的二進位制包頭包體,以及序列號反序列化的細節

無論如何,瞭解協議設計的原則,對深入理解系統通訊非常有幫助。今天就以即時通訊(後稱im)為例,講講應用層的協議選型。

一、im協議的分層設計 所謂“協議”是雙方共同遵守的規則,例如:離婚協議,停戰協議。協議有語法、語義、時序三要素。 (1)語法:即資料與控制資訊的結構或格式 (2)語義:即需要發出何種控制資訊,完成何種動作以及做出何種響應 (3)時序

:即事件實現順序的詳細說明

im協議設計分為三層:應用層、安全層、傳輸層。

分別看下這三層的協議應該如何選型。

二、im應用層協議設計 應用層協議選型,常見的有三種:文字協議、二進位制協議、流式XML協議。 (1)文字協議 文字協議是指 “貼近人類書面語言表達”的通訊傳輸協議,典型的協議是http協議,一個http協議大致長成這樣:

GET / HTTP/1.1
User-Agent: curl
Host: musicml.net
Accept: */*

文字協議的特點是: a.可讀性好,便於除錯 b.擴充套件性也好(通過key:value擴充套件) c.解析效率一般(一行一行讀入,按照冒號分割,解析key和value) d.對二進位制的支援不好 ,比如語音/視訊 im中,msn使用的是文字協議。

(2)二進位制協議 二進位制協議是指binary協議,典型是ip協議,以下是ip協議的一個圖示:

二進位制協議一般定長包頭和可擴充套件變長包體 ,每個欄位固定了含義 ,例如IP協議的前4個bit表示協議版本號 (Version)。 二進位制協議有這樣一些特點: a.可讀性差,難於除錯 b.擴充套件性不好 ,如果要擴充套件欄位,舊版協議就不相容了,所以一般設計時會有一個Version欄位 c.解析效率超高(幾乎沒有解析代價) 對二進位制的支援不好 ,比如語音/視訊 im中,QQ使用的時二進位制協議。

(3)流式XML協議 im的準標準協議xmpp就是使用流式XML,像gtalk,校內通這些im都是基於xmpp的,讓我們來看一個xmpp協議的例子:

<message
to=’[email protected]’
from=’[email protected]’
type=’chat’
xml : lang=’en’>
<body>Wherefore art thou, Romeo?</body>
</message>

從xml標籤中大致可以判斷這是一個romeo發給juliet的聊天訊息。 xmpp協議可以實現跨域的互通。例如gtalk和校內通使用者聊天。只要服務端實現了s2s服務(server to server) ,不過現在的im基本沒有互通需求 ,所以這個服務基本沒有人實現。 Xmpp協議有幾個特點: a.它是準標準協議,可以跨域互通 b.XML的優點,可讀性好,擴充套件性好 c.解析代價超高(dom解析) d.有效資料傳輸率超低(大量的標籤) 個人旗幟鮮明的強烈不建議使用xmpp,特別是無線端im,如果要用,一定要自己做壓縮 ,減少網路流量(用過xmpp的同學都清楚,發一個登入包需要多少互動,要浪費多少流量)。

實際的栗子 下面來看一個im協議的實際例子 ,一般常見的做法是:定長二進位制包頭,可擴充套件變長包體。 包體可以使用用文字、XML等擴充套件性好的協議。 包頭負責傳輸和解析效率,與業務無關。包體保證擴充套件性,與業務相關。

這是一個實際的16位元組im二進位制定長包頭

//sizeof(cs_header)=16
struct cs_header
{
uint32_t version;
uint32_t magic_num;
uint32_t cmd;
uint32_t len;
uint8_t data[];
}__attribute__((packed));

a.前4個位元組是version; b.接下來的4個位元組是個“魔法數字(magic_num)“,用來保證資料錯位或丟包問題,常見的做法是,包頭放幾個約定好的特殊字元,包尾放幾個約定好的特殊字元 約定好,發給你的協議,某幾個位元組位置,是0x 01020304 ,才是正常報文; c.接下來是command(命令號),用來區分是keepalive報文、業務報文、金鑰交換報文等; d.len(包體長度),告知服務端要接收多長的包體。

這是一個實際的可擴充套件im變長包體

message CUserLoginReq
{
optional string username = 1;
optional string passwd = 2;
}
message CUserLoginResp
{
optional uint64 uid =1;
}

使用的是google的Protobuf協議,可以看到,登入請求包傳入的是使用者名稱與密碼,登入響應包返回的是使用者的uid。 當然,除了Protobuf,可選擇的可擴充套件包體協議還有xml、json、mcpack(這...)等。 個人旗幟鮮明的推薦使用Protobuf,主要有幾個原因: a.現成的解析庫種類多,可以生成C++、Java、php等程式碼 b.自帶壓縮功能 c.在工業界已廣泛應用 d.google製造

三、im安全層協議設計 im協議,訊息的保密性非常重要 ,誰都不希望自己聊天內容被看到,所以安全層是必不可少的。 1、SSL 證書管理微微複雜,代價有點高。

2、自行加解密 自己來搞加解密,核心在於金鑰的生成與管理,金鑰管理方式有多種,主要有這麼三種: (1)固定金鑰 服務端和客戶端約定好一個金鑰,同時約定好一個加密演算法(eg:AES ),每次客戶端im在傳送前,就用約定好的演算法,以及約定好的金鑰加密再傳輸,服務端收到報文後,用約定好的演算法,約定好的金鑰再解密。這種方式,金鑰和演算法對程式設計師都是透明的。

(2)一人一金鑰 簡單說來就是每個人的金鑰是固定的,但是每個人之間又不同,其實就是在固定金鑰的演算法中包含使用者的某一特殊屬性,比如使用者uid、手機號、qq號等。

(3)動態金鑰(一session一金鑰) 動態金鑰,一Session一金鑰的安全性更高,每次會話前協商金鑰。 金鑰協商的過程要經過2次非對稱金鑰的隨機生成,1次對稱加密金鑰的隨機生成,具體詳情這裡不展開,有興趣的同學可以看下SSL金鑰協商額過程。

四、im傳輸層協議設計 可選的協議有TCP和UDP 現在的im傳輸層基本都是使用TCP,有了epoll等技術後,多連線就不是瓶頸了,單機幾十萬連結沒什麼問題。

先聊這麼多,希望對大夥進行應用/安全/傳輸層協議選型有幫助。