通過 wireshark 抓包瞭解直播流媒體 RTMP 協議基本過程

聲網Agora發表於2019-06-12

作者:Elias Zhang 聲網資深工程師,擁有從Iaas層的基礎資訊儲存服務到paas層的雲服務的職業經歷,喜歡python語言,習慣使用C#,熟悉基於和結合CDN的業務產品架構,點播、直播、雲導播等。喜歡探索問題和研究創新,擁有5項國家發明專利。

在直播是最常見的實時音視訊場景,而 RTMP 是該場景下最重要的協議之一,是很多初步接觸實時音視訊的開發者需要了解的。本文會一邊利用 winshark工具進行抓包,一邊從中分析 RTMP 協議的基本原理,幫助大家更容易地理解它。

先給出RTMP協議的原檔案 www.adobe.com/devnet/rtmp… 需要用到的時候可以參考一下~。

做推流直播接觸最多的並且最主要是RTMP協議

  • RTMP協議是應用層協議,是要靠底層可靠的傳輸層(TCP)
  • 協議(通常是TCP)來保證資訊傳輸的可靠性的。在基於傳輸層協議的連結建立完成後,RTMP協議也要客戶端和伺服器通過“握手”來建立基於傳輸層連結之上的RTMP Connection連結. 播放一個RTMP協議的流媒體需要經過以下幾個步驟:握手,建立網路連線,建立網路流,播放。伺服器和客戶端之間只能建立一個網路連線,但是基於該連線可以建立很多網路流。他們的關係如圖所示:

通過 wireshark 抓包瞭解直播流媒體 RTMP 協議基本過程

  • RTMP協議傳輸時會對資料做自己的格式化,這種格式的訊息我們稱之為RTMP Message,而實際傳輸的時候為了更好地實現多路複用、分包和資訊的公平性,傳送端會把Message劃分為帶有Message ID的Chunk,每個Chunk可能是一個單獨的Message,也可能是Message的一部分,在接受端會根據chunk中包含的data的長度,message id和message的長度把chunk還原成完整的Message,從而實現資訊的收發。 協議本身的詳細欄位和流程就不在這裡詳細解釋了,主要結合看包直觀的瞭解下這個協議的流程,更詳細的內容可以查閱前面給出的官方文件。

RTMP步驟:

1. 握手

要建立一個有效的RTMP Connection連結,首先要“握手”:客戶端要向伺服器傳送C0,C1,C2(按序)三個chunk,伺服器向客戶端傳送S0,S1,S2(按序)三個chunk,然後才能進行有效的資訊傳輸。RTMP協議本身並沒有規定這6個Message的具體傳輸順序,但RTMP協議的實現者需要保證這幾點:

  • 客戶端要等收到S1之後才能傳送C2
  • 客戶端要等收到S2之後才能傳送其他資訊(控制資訊和真實音視訊等資料)
  • 服務端要等到收到C0之後傳送S1
  • 服務端必須等到收到C1之後才能傳送S2
  • 服務端必須等到收到C2之後才能傳送其他資訊(控制資訊和真實音視訊等資料) 握手開始於客戶端傳送C0、C1塊。伺服器收到C0或C1後傳送S0和S1。 當客戶端收齊S0和S1後,開始傳送C2。當伺服器收齊C0和C1後,開始傳送S2。 當客戶端和伺服器分別收到S2和C2後,握手完成。

通過 wireshark 抓包瞭解直播流媒體 RTMP 協議基本過程

實際上真實發包如下:

通過 wireshark 抓包瞭解直播流媒體 RTMP 協議基本過程

我們可以看見TCP的三次握手,RTMP基於TCP的可靠傳輸。

通過 wireshark 抓包瞭解直播流媒體 RTMP 協議基本過程

接下去過濾rtmpt協議,rtmp的握手過程如下,我們發現真實發包是C0+C1一起發;S0,S1,S2一起發。

2. 建立網路連線(NetConnection)

通過 wireshark 抓包瞭解直播流媒體 RTMP 協議基本過程

通過 wireshark 抓包瞭解直播流媒體 RTMP 協議基本過程

a) 客戶端傳送命令訊息中的“連線”(connect)到伺服器,請求與一個服務應用例項建立連線。

通過 wireshark 抓包瞭解直播流媒體 RTMP 協議基本過程

開啟connect這個包,一個OSI5層協議模型,最後一個是RTMP協議傳送了connect連結訊息,檢視內容包含推流地址名,但是可以觀察到還沒有發流名,地址是有app名。

觀察一下RTMP的包頭

通過 wireshark 抓包瞭解直播流媒體 RTMP 協議基本過程

StreamID是每個訊息的唯一標識,劃分成Chunk和還原Chunk為Message的時候都是根據這個ID來辨識是否是同一個訊息的Chunk的,這裡面為0說明這個訊息是初始的0訊息。

通過 wireshark 抓包瞭解直播流媒體 RTMP 協議基本過程

Chunk stream ID:message會拆分成多個chunk,同一個Chunk Stream ID必然屬於同一個Message。

通過 wireshark 抓包瞭解直播流媒體 RTMP 協議基本過程

message type id(訊息的型別id):表示實際傳送的資料的型別,如8代表音訊資料、9代表視訊資料。

Format:指的是chunk type。共有4種不同的格式,其中第一種格式欄位為0,可以表示其他三種表示的所有資料,但由於其他三種格式是基於對之前chunk的差量化的表示,因此可以更簡潔地表示相同的資料,實際使用的時候還是應該採用儘量少的位元組表示相同意義的資料。因為type0是表示不同資料,其他是差量,所以可以想象如果搜不到type0的包說明這個流肯定有問題。可以通過“rtmpt.header.format == 0”過濾。

b) 伺服器接收到連線命令訊息後,傳送確認視窗大小(Window Acknowledgement Size)協議訊息到客戶端,同時連線到連線命令中提到的應用程式。

c) 伺服器傳送設定頻寬協議訊息到客戶端。

d) 客戶端處理設定頻寬協議訊息後,傳送確認視窗大小(Window Acknowledgement Size)協議訊息到伺服器端。

e) 伺服器傳送使用者控制訊息中的“流開始”(Stream Begin)訊息到客戶端。

f) 伺服器傳送命令訊息中的“結果”(_result),通知客戶端連線的狀態。 b~f如圖:在_result我們可以看到連結已經建立成功

通過 wireshark 抓包瞭解直播流媒體 RTMP 協議基本過程

接下去的包我們看到發了releaseStream命令,裡面的agora就是流名,所以一個推流地址我們可以抓包connect和releaseStream裡面拼接得出。

通過 wireshark 抓包瞭解直播流媒體 RTMP 協議基本過程

  1. 建立一個網路流(NetStream)

通過 wireshark 抓包瞭解直播流媒體 RTMP 協議基本過程

提示:網路流代表了傳送多媒體資料的通道。伺服器和客戶端之間只能建立一個網路連線,且多個網路流可以複用這一個網路連線。

a. 客戶端向伺服器傳送請求建立流(createStream)。

通過 wireshark 抓包瞭解直播流媒體 RTMP 協議基本過程

b. 伺服器收到請求後向客戶端傳送_result(),對建立流的訊息進行響應。此時NetStream建立完成。

通過 wireshark 抓包瞭解直播流媒體 RTMP 協議基本過程

4. PLAY 播放

通過 wireshark 抓包瞭解直播流媒體 RTMP 協議基本過程

a) 客戶端傳送命令訊息中的“播放”(play)命令到伺服器。

通過 wireshark 抓包瞭解直播流媒體 RTMP 協議基本過程

b) 接收到播放命令後,伺服器傳送設定塊大小(ChunkSize)協議訊息。

c) 伺服器傳送使用者控制訊息中的“streambegin”,告知客戶端流ID。

d) 播放命令成功的話,伺服器傳送命令訊息中的“響應狀態” NetStream.Play.Start & NetStream.Play.reset,告知客戶端“播放”命令執行成功。

通過 wireshark 抓包瞭解直播流媒體 RTMP 協議基本過程

e) 在此之後伺服器傳送客戶端要播放的音訊和視訊資料。

通過 wireshark 抓包瞭解直播流媒體 RTMP 協議基本過程

可以注意到裡面音訊type是8,視訊是9。

5. PUBLISH 推流

通過 wireshark 抓包瞭解直播流媒體 RTMP 協議基本過程
推流從握手開始和前面步驟123一致。

和第四步play區別在於netstream的命令改為publish

通過 wireshark 抓包瞭解直播流媒體 RTMP 協議基本過程

通過 wireshark 抓包瞭解直播流媒體 RTMP 協議基本過程

關於本文,如果你在跟隨步驟操作或閱讀時有任何疑問,請點選這裡跳轉至原文與作者直接交流。

相關文章