im協議設計選型【轉】

1、im協議的分層設計
所謂「協議」是雙方共同遵照的規則,例如:離婚協議,停戰協議。協議有語法、語義、時序三要素。
(1)語法:即數據與控制信息的結構或格式
(2)語義:即須要發出何種控制信息,完成何種動做以及作出何種響應
(3)時序:即事件實現順序的詳細說明
今天的重點是在「協議選型」上,重點講選哪一種協議。php

im協議設計主要分爲三層:應用層、安全層、傳輸層

後文將詳細介紹這三層的協議應該如何選型與設計。程序員

2、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使用的時二進制協議。json

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

<message
to=’romeo@example.net’
from=’juliet@example.com’
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));
前4個字節是version;
接下來的4個字節是個「魔法數字(magic_num)「,用來保證數據錯位或丟包問題,常見的作法是,包頭放幾個約定好的特殊字符,包尾放幾個約定好的特殊字符 約定好,發給你的協議,某幾個字節位置,是0x 01020304 ,纔是正常報文;
接下來是command(命令號),用來區分是keepalive報文、業務報文、密鑰交換報文等;
len(包體長度),告知服務端要接收多長的包體。網絡

這是一個實際的可擴展im變長包體:
message CUserLoginReq
{
optional string username = 1;
optional string passwd = 2;
}session

message CUserLoginResp
{
optional uint64 uid =1;
}
使用的是google的Protobuf協議(玩過的人都懂),能夠看到,登陸請求包傳入的是用戶名與密碼,登陸響應包返回的是用戶的uid。
固然,除了Protobuf,可選擇的可擴展包體協議還有xml、json、mcpack(你們懂?)等。
我的旗幟鮮明的推薦Protobuf,主要有幾個緣由:
a.現成的解析庫種類多,能夠生成C++、Java、php等代碼
b.自帶壓縮功能
c.在工業界已普遍應用
d.google製造dom

3、im安全層協議設計
im協議,消息的保密性很是重要 ,誰都不但願本身聊天內容被看到,因此安全層是必不可少的。
一、SSL
證書管理微微複雜,代價有點高。

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

(2)一人一密鑰
簡單說來就是每一個人的密鑰是固定的,可是每一個人之間又不一樣,其實就是在固定密鑰的算法中包含用戶的某一特殊屬性,好比用戶uid、手機號、qq號等。

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

4、im傳輸層協議設計
可選的協議有TCP和UDP
如今的im傳輸層基本都是使用TCP,有了epoll等技術後,多鏈接就不是瓶頸了,單機幾十萬連接沒什麼問題。58同城如今線上單機鏈接好像是10w?(可能單機性能測試能夠到百萬,線上通常跑到幾十萬)

關於QQ使用UDP的問題
我的不清楚QQ使用UPD的初衷,但猜想是由於10多年前C10K問題沒有獲得很好解決,一臺服務器支撐不了1W個TCP鏈接 ,騰訊的同時在線量高,沒辦法,只有用UDP了 ,但UDP又不可靠,故只能在UDP上實現TCP的超時/重傳/確認等機制

5、收尾
關於QQ使用UDP協議,在討論的過程當中,有同窗提出了一個很是好的問題「無線環境下,UDP更好,能夠作到狀態無關,而TCP不穩定,進出電梯就要斷線,用戶體驗很差」。
其實吧,「用戶狀態能夠設計的與鏈接狀態無關」,若是你們感興趣,後續我能夠撰文和你們聊一聊,傳輸層使用TCP,怎麼作到在線狀態與底層鏈接無關。

 

原文:http://www.habadog.com/2015/05/20/im-protocol-choose/

相關文章
相關標籤/搜索