RTMP詳細分析(Message 消息,Chunk分塊)
librtmp分析(發送數據包處理)
librtmp分析(接收數據包處理)
RTMP協議是Real Time Message Protocol(實時信息傳輸協議)的縮寫,它是由Adobe公司提出的一種應
用層的協議,用來解決多媒體數據傳輸流的多路復用(Multiplexing)和分包(packetizing)的問題。隨
著VR技術的發展,視頻直播等領域逐漸活躍起來,RTMP作為業內廣泛使用的協議也重新被相關開發者重
視起來。
目錄
- 1、介紹:
- 2.1、握手:
- 2.2、握手過程:
- 3.1 、C0和S0格式(簡單握手):
- 3.2 、C1和S1格式(簡單握手):
- 3.3 、C2和S2格式(簡單握手):
- 4、復雜握手:
1、介紹:
RTMP協議是應用層協議,是要靠底層可靠的傳輸層協議(通常是TCP)來保證信息傳輸的可靠性的。在
基于傳輸層協議的鏈接建立完成后,RTMP協議也要客戶端和服務器通過“握手”來建立基于傳輸層鏈接之
上的RTMP Connection鏈接,在Connection鏈接上會傳輸一些控制信息,如
SetChunkSize,SetACKWindowSize。其中CreateStream命令會創建一個Stream鏈接,用于傳輸具體的
音視頻數據和控制這些信息傳輸的命令信息。RTMP協議傳輸時會對數據做自己的格式化,這種格式的消
息我們稱之為RTMP Message,而實際傳輸的時候為了更好地實現多路復用、分包和信息的公平性,發送
端會把Message劃分為帶有Message ID的Chunk,每個Chunk可能是一個單獨的Message,也可能是
Message的一部分,在接受端會根據chunk中包含的data的長度,message id和message的長度把
chunk還原成完整的Message,從而實現信息的收發。
2.1、握手:
一個 RTMP 連接以握手開始。RTMP 的握手不同于其他協議? RTMP 握手由三個固定
長度的塊組成,而不是像其他協議一樣的帶有報頭的可變長度的塊。
客戶端 (發起連接請求的終端) 和服務器端各自發送相同的三塊。
客戶端發送的這些塊稱為C0、 C1 和 C2,服務器端發送的這些塊稱為 S0、
S1 和 S2。
2.2、握手過程:
本身并沒有規定這6個Message的具體傳輸順序,但RTMP協議的實現者需要保證這幾點:
客戶端要等收到S1之后才能發送C2
客戶端要等收到S2之后才能發送其他信息(控制信息和真實音視頻等數據)
服務端要等到收到C0之后發送S1
服務端必須等到收到C1之后才能發送S2
服務端必須等到收到C2之后才能發送其他信息(控制信息和真實音視頻等數據)
理論上來講只要滿足以上條件,如何安排6個Message的順序都是可以的,但實際實現中為了在保證握手
的身份驗證功能的基礎上盡量減少通信的次數,一般的發送順序是這樣的,這一點可以通過wireshark抓推流包進行驗證:
握手流程圖:
Uninitialized (未初始化):協議的版本號在這個階段被發送。客戶端和服務器都是。
uninitialized (未初始化)狀態。之后客戶端在數據包 C0 中將協議版本號發出。如果服務器
支持這個版本,它將在回應中發送S0 和 S1。如果不支持,服務器會才去適當的行為進
行響應。在 RTMP 協議中,這個行為就是終止連接。
Version Sent (版本已發送):在未初始化狀態之后,客戶端和服務器都進入 Version Sent
(版本已發送) 狀態。客戶端會等待接收數據包 S1 而服務器在等待 C1。一旦拿到期待的包,
客戶端會發送數據包 C2 而服務器發送數據包 S2。 (客戶端和服務器各自的)狀態隨即變為
Ack Sent (確認已發送 )。
Ack Sent (確認已發送):客戶端和服務器分別等待 S2 和 C2。
Handshake Done (握手結束):客戶端和服務器可以開始交換消息了。
3.1 、C0和S0格式(簡單握手):
C0 和 S0 包都是一個單一的八位字節,以一個單獨的八位整型域進行處理:
版本( 八位):在 C0 中,這一字段指示出客戶端要求的 RTMP 版本號。
在 S0 中,這一字段指示出服務器端選擇的 RTMP 版本號。版本號基本都是3。
0、1、2 這三個值是由早期其他產品使用的,是廢棄值。
4 - 31 被保留為RTMP 協議的未來實現版本使用。
32 - 255 不允許使用 (以區分開 RTMP 和其他常以一個可打印字符開始的文本協議)。
無法識別客戶端所請求版本號的服務器應該以版本 3 響應, (收到響應的) 客戶端可以選擇降低到版本 3,或者放棄握手。
3.2 、C1和S1格式(簡單握手):
C1 和 S1 數據包的長度都是 1536 字節,分布如下:
Time (四個字節):這個字段包含一個 timestamp,用于本終端發送的所有后續塊的時間
起點。這個值可以是 0。
Zero (四個字節):這個字段必須都是 0。
Random data (1528 個字節):這個字段可以包含任意值。終端需要區分出響應來自它發
起的握手還是對端發起的握手,這個數據應該發送一些足夠隨機的數。這個不需要對隨機數進行加密保護,也不需要動態值。
3.3 、C2和S2格式(簡單握手):
C2 和 S2 數據包長度都是 1536 個節,基本就是 S1 和 C1 的副本。分布如下:
Time (四個字節):這個字段必須包含終端在 S1 (給 C2) 或者 C1 (給 S2) 發的
timestamp。
Time2 (四個個節):這個字段必須包含終端先前發出數據包 (s1 或者 c1) timestamp。
Random echo (1528 個字節):這個字段必須包含終端發的 S1 (給 C2) 或者 S2 (給 C1)
的隨機數。
4、復雜握手:
復雜握手主要是增加了更嚴格的驗證。
主要是將簡單握手中1528Bytes隨機數的部分平均分成兩部分,
一部分764Bytes存儲public key(公共密鑰),另一部分
764Bytes存儲digest(密文, 32字節)。
另外, 復雜握手還有一個明顯的特征就是: Version部分不為0,
服務器端可根據這個來判斷是否簡單握手或復雜握手。