理解RTMP協議——握手鍊接

本文梳理了理解RTMP協議的基本概念
訪問 個人博客瞭解更多

RTMP 的通訊機制

rtmp 客戶端與服務端通訊的機制

下圖是播放器與 rtmp 服務端通訊的例子html

另外推薦閱讀 nginx-rtmp-module 源碼,好比,握手協議相關代碼在 ngx_rtmp_handshake.c 文件nginx

RTMP 的握手鍊接的例子

step 1, tcp 三次握手

TCP 握手過程這裏不詳細展開,參考這篇文章 TCP 的那些事兒git

step 2, RTMP 握手驗證

RTMP 握手起到驗證的做用,RTMP 握手方式主要分爲:簡單握手與複雜握手github

Adobe 協議中描述的是簡單握手,而 Adobe 產品 Flash Media Server 採用複雜握手的方式shell

簡單握手

與流程圖有點不一樣,握手的實際流程分三個步驟:服務器

  • 第一步, Client -> Server,內容是 C0+C1
  • 第二步, Server -> Client,內容是 S0+S1+S2
  • 第三步, Client -> Server,內容是 C2

我使用 Wireshark 抓包,驗證了過程(我使用 nginx-rtmp-module 作服務器,ffmpeg推流,VLC Media Play播放)網絡

報文的解釋:dom

C0 與 S0
    +-+-+-+-+-+-+-+-+
    |  version      |
    +-+-+-+-+-+-+-+-+
  • C0 與 S0tcp

    • C0:客戶端發送其所支持的 RTMP 版本號:3~31。通常都是寫 3
    • S1:服務端返回其所支持的版本號。若是沒有客戶端的版本號,默認返回 3
C1 與 S1
    +-+-+-+-+-+-+-+-+-+-+
    |   time (4 bytes)  |
    +-+-+-+-+-+-+-+-+-+-+
    |   zero (4 bytes)  |
    +-+-+-+-+-+-+-+-+-+-+
    |   random bytes    |
    +-+-+-+-+-+-+-+-+-+-+
    |random bytes(cont) |
    |       ....        |
    +-+-+-+-+-+-+-+-+-+-+
  • C1 與 S1post

    • C1/S1 長度爲 1536B。主要目的是確保握手的惟一性。
    • 格式爲 time + zero + random
    • time 發送時間戳,長度 4 byte
    • zero 保留值 0,長度 4 byte
    • random 隨機值,長度 1528 byte,保證這次握手的惟一性,肯定握手的對象
C2 與 S2
    +-+-+-+-+-+-+-+-+-+-+
    |   time (4 bytes)  |
    +-+-+-+-+-+-+-+-+-+-+
    |   time2(4 bytes)  |
    +-+-+-+-+-+-+-+-+-+-+
    |   random bytes    |
    +-+-+-+-+-+-+-+-+-+-+
    |random bytes(cont) |
    |       ....        |
    +-+-+-+-+-+-+-+-+-+-+
  • C2 與 S2

    • C2/S2 的長度也是 1536B。至關於就是 S1/C1 的響應值,對應 C1/S1 的 Copy 值,在於字段有點區別
    • time, C2/S2 發送的時間戳,長度 4 byte
    • time2, S1/C1 發送的時間戳,長度 4 byte
    • random,S1/C1 發送的隨機數,長度爲 1528B

RTMP 是用於網絡傳輸的二進制協議,默認使用 Big-Endian 格式,由於 Big-Endian 格式在抓包時可讀性較好

複雜握手

對於複雜握手,不使用 Adobe 產品 FMS 的話,簡單瞭解便可

相對於簡單握手,複雜握手增長了嚴格的驗證,主要是 random 字段上進行更細化的劃分

1528Bytes隨機數的部分平均分紅兩部分,一部分764Bytes存儲public key(公共密鑰),另外一部分764Bytes存儲digest(密文,32字節)。

從二進制報文的角度,判斷複雜握手的特徵是,Version部分不爲0,服務器端可根據這個來判斷是否簡單握手或複雜握手。

握手的瞭解到這裏,下面繼續看看握手以後的步驟

step 3, RTMP connect

RTMP 有一個重要的概念:Application Instance,直觀上,能夠體如今 rtmp 的 url 上

我測試的推流例子,用到的 url 爲: rtmp://192.168.23.152/live/movie

你們能夠注意到,上面 wireshark 對 rtmp 抓包的截圖中,握手後緊接一個 client->server 的報文 connect('live')

1909    36.398483095    192.168.23.152    192.168.23.152    RTMP    282    connect('live')

而這個 live 就是此次推流的 Application Instance

step 4, createStream(建立流) --- 建立邏輯通道

上面 wireshark 對 rtmp 抓包的截圖中,有下面兩行,第一行是 client->server,第二行是 server->client

1933    36.484940956    192.168.23.152    192.168.23.152    RTMP    105    Window Acknowledgement Size 5000000|createStream()
1935    36.485004644    192.168.23.152    192.168.23.152    RTMP    109    _result()
1946    36.528398367    192.168.23.152    192.168.23.152    RTMP    168    getStreamLength()|play('movie')|Set Buffer Length 1,3000ms

直觀地,rtmp://192.168.23.152/live/movie 的 movie 是此次拉流的 stream

createStream 命令用於建立邏輯通道,該通道用於傳輸視頻、音頻、metadata。在服務器的響應報文 _result() 中會返回Stream ID,用於惟一的標示該Stream。

getStreamLength 命令用來獲取 movie 的流的長度

Real Time Messaging Protocol (AMF0 Command getStreamLength())
    RTMP Header
    RTMP Body
        String 'getStreamLength'
        Number 3
        Null
        String 'movie'
Real Time Messaging Protocol (AMF0 Command play('movie'))
    RTMP Header
    RTMP Body
        String 'play'
        Number 4
        Null
        String 'movie'
        Number -2000

根據 Adobe’s Real Time Messaging Protocol 裏對 _result 命令的定義,上面 body 中第四個字段 "Number 1" 即是這次的 Stream ID

step n,anything

通常的 rtmp 鏈接的流程,都如上所示,後面即是命令與音視頻數據的消息,好比:

  • 播放器的客戶端發送play命令來播放指定流,等待服務端傳輸音視頻數據。
  • 推流的客戶端會發送 publish 命令,開始上傳音視頻數據。

step last, deleteStream(刪除流)

根據 Adobe’s Real Time Messaging Protocol

NetStream sends the deleteStream command when the NetStream object is getting destroyed.
當 NetStream 對象銷燬的時候發送刪除流命令。

好比,播放器客戶端中止播放,能夠刪除指定Stream ID的流。服務器不用對這條命令發送響應報文。

Reference

相關文章
相關標籤/搜索