消息(Message Payload)
若一条消息(消息负载(Message Payload))长度超过 Chunk Size,消息将被拆分为多个块(Chunk),数据存储在chunk data里,接收端接收完成后,会重新组成消息。
示例:消息长度=300字节,Chunk Size=128 → 拆分为3块(128+128+44)
消息格式
消息由 消息头+消息体构成,消息体由消息头决定。
负载信息(消息)类型同前面的分块消息头(chunk message header)的中 Message Type ID 类型。
(chunk message header)
| 字段 | 字节数 | 说明 |
|--------------------|--------|----------------------------------------------------------------------|
| Timestamp | 3 | 消息的绝对时间戳(单位:毫秒)。若 ≥ 0xFFFFFF,则固定为0xFFFFFF,需扩展为4字节(见后) |
| Message Length | 3 | 消息的总长度(单位:字节) |
| Message Type ID | 1 | 消息类型(如 8=音频,9=视频,18=AMF命令等) |
| Stream ID | 4 | 消息所属流的ID(小端序存储) |
消息头
消息头共占11Byte,包含如下数据:
- 消息类型:占1Byte,取值[1,7],专用于协议控制消息,和分块chunk message header中的 Message Type ID 类型相同,类型0和1是分块专用,3-6是RTMP消息专用,类型7用于服务器通讯。
- 载荷数据长度:占3Byte, 表示消息中载荷数据所占字节数。
- 时间戳:占4Byte,表示该消息的时间戳
- 消息流ID: 占3Byte, 表示该消息所在的消息流ID.
消息体是实际传输的数据, 消息类型 定义,常见类型如下:
| 消息类型 | 内容 |
| 1 | set chunk size 设置分块大小 |
| 2 | Abort Message 丢弃消息 |
| 3 | Acknowledgement 响应消息 |
| 4 | User control message 用户控制消息 |
| 5 | Window Acknowledgement Size 窗口响应大小 |
| 6 | 设置对方带宽 |
| 8 | 音频消息 |
| 9 | 视频消息 |
| 15、18 | 数据消息(元数据、其他用户数据) |
| 16、19 | 共享消息 |
| 17、20 | Command Message Message 命令消息 |
| 22 | 聚合消息(将多条消息合并在一个分块传递) |
比如音频消息体
Chunk Header (Type 0):
fmt=0b00, Chunk Stream ID=3
Timestamp=0xFFFFFF → 触发扩展
Message Length=500 → 0x01F4
Message Type=0x08(音频)
Stream ID=0x00000002
Extended Timestamp: 0x01000000 → 16777216ms
Payload: AAC音频帧(500字节)
消息类型
设置分块大小-Set Chunk Size(type 1)
| 消息主体大小 | 字节数 | 描述 |
|---|---|---|
| Message Body | 4 字节大端序整数 | 设置新的块大小(单位:字节) |
有效范围
- 块大小范围:1 ~ 0xFFFFFFFF()(即 1 ~ 4,294,967,295 字节)。
- 实际应用中,默认128字节,最大65536字节。通常不会设置极大值(避免内存或网络问题)。
生效时机
- 接收方在解析到该消息后,立即生效,后续分块按新大小处理。
双向控制
- 客户端和服务器均可发送 Set Chunk Size,双方的分块大小可独立设置。
- 例如:客户端设置 发送块大小=4096,服务器设置 发送块大小=2048
Chunk Header (Type 0):
fmt=0b00, Chunk Stream ID=3
Timestamp=0xFFFFFF → 触发扩展
Message Length=4 → 0x04
Message Type=0x01(设置分块大小)
Stream ID=0x00000001
Extended Timestamp: 0x01000000 → 16777216ms
Payload: 4字节
丢弃消息-Abort Message(type 2)
当一个分块流(Chunk Stream)的传输被意外中断(如推流断开、网络错误)时,接收方可能已收到该流的 部分分块数据。此时发送方需通过 Abort Message 通知接收方:
- 丢弃未完成数据:清理残留在接收缓冲区中的不完整分块。
- 释放资源:避免无效数据占用内存或阻塞后续传输。
- 快速恢复:为同一 Chunk Stream ID 的新数据传输扫清障碍。
| Message Body | 4 字节小端序整数 | 需丢弃的分块流ID(Chunk Stream ID),对应 Chunk Header 中的 Chunk Stream ID |
响应消息-Acknowledgement (type 3)
用于 带宽控制 和 流量管理 的关键机制,接收方通过此消息通知发送方已成功接收的字节数,帮助发送方动态调整传输速率以避免网络拥塞。
- 流量控制:接收方周期性反馈已接收的数据量,发送方根据此信息调整发送速率。
- 避免拥塞:防止发送方速率超过接收方处理能力或网络带宽上限。
- 可靠性增强:在弱网环境下辅助检测丢包或延迟。
| Message Body | 4 字节大端序整数 | 已接收字节数 |
窗口响应大小-Window Acknowledgement Size (type 5)
窗口响应大小是流量控制的关键机制,用于管理数据传输速率和防止接收方被数据淹没。双方建立连接后服务端发送 窗口响应大小 告知接收端窗口响应大小,客户端达接收到此大小的数据后,必须响应消息(类型3)。
比如:服务器希望向客户端发送1024Byte数据后,客户端需要返回Acknowledgement确认消息,以达到流量控制的目的:
- 窗口大小:接收方在需要确认前可以接收的最大字节数
- 确认机制:接收方定期发送确认包(上面的类型3 Acknowledgement)
- 流量控制:防止发送方过快地发送数据
| Message Body | 4 字节大端序整数 | 窗口响应大小 |
设置对方宽带-Set Peer Bandwidth (type 6)
如果接收端的窗口响应需要和发送端(服务器)不同时,则接收端需要反过来设置发送端的宽带,占用5Byte。
| 字段 | 大小(字节) | 描述 |
|---|---|---|
| Window Size | 4 | 窗口大小(字节) |
| Limit Type | 1 | 限制类型 |
限制类型可取值0,1或2,含义如下:
- 0:硬限制,消息接收端必须以规定带宽发送数据
- 1:软限制,带宽由接收端决定,发送端可对其加以限制
- 2:动态限制,消息接收可以为硬限制,也可以是软限制。
用户控制消息-User Control Messages(type 4)
发送端通过用户控制消息想接收端发送关于用户控制事件的消息,长度可变,包含事件类型和事件数据两部分,事件类型占用2字节,其余为事件数据。
| 字段 | 大小(字节) | 描述 |
|---|---|---|
| Event Type | 2 | 事件类型 |
| Event Data | 可变 | 事件数据 |
分为7种事件类型:
| 事件类型 | 名称 | 事件数据 | 描述 |
|---|---|---|---|
| 0 | Stream Begin | 流ID | 流已就绪 |
| 1 | Stream EOF | 流ID | 流已结束 |
| 2 | Stream Dry | 流ID | 媒体流数据不足,服务端没有足够的数据发给客户端 |
| 3 | Set Buffer Length | 流ID + 缓冲区长度 | 设置缓冲区大小,开始处理流之前,客户端告知服务器缓冲区大小 |
| 4 | Stream Is Recorded | 流ID | 当前流为录播流 |
| 6 | Ping Request | 时间戳 | 检测客户端是否在线,携带服务器时间戳 |
| 7 | Ping Response | 时间戳 | 客户端向服务器响应消息,表示在线 |
共享对象消息-Shared Object Messages (type 16/19)
一种强大的实时数据同步机制,允许多个客户端通过服务器同步共享数据状态
| 类型值 | 名称 | 方向 | 描述 |
|---|---|---|---|
| 0x01 | Connect | C→S | 客户端请求连接共享对象 |
| 0x02 | Disconnect | C→S | 客户端断开共享对象 |
| 0x03 | Set Attribute | C↔S | 客户端设置共享对象属性 |
| 0x04 | Update Data | S→C | 服务器通知除源客户端外的所有客户端更新共享数据 |
| 0x05 | Update Attribute | S→C | 客户端设置Set Attribute 成功后,服务器会返回成功,更新属性值 |
| 0x06 | Send Message | C↔S | 客户端请求服务器向所有客户端广播(发送)消息到共享对象 |
| 0x07 | Status | S→C | 状态通知 |
| 0x08 | Clear Data | S→C | 服务器通知客户端清除所有数据 |
| 0x09 | Delete Data | S→C | 服务器通知客户端删除特定数据(插槽) |
| 0x0A | Delete Data sucess | C→S | 客户端返回删除成功 |
| 0x0B | Connect sucess | S→C | 服务器发送连接成功事件 |
消息头:
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| 类型 (1) | 共享对象名称 (变长) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| 版本 (4) | 持久化标志 (1) | 保留 (3) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Set Attribute 消息体
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| 属性名长度 (2) | 属性名 (变长) | 属性类型 (1) | 属性值 (变长) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
命令消息类型(Type 17/19)
命令消息类型 17 和 19 是 AMF3 编码的命令消息,分别用于客户端到服务器和服务器到客户端的通信。
- 类型 17:客户端发起的命令请求
- 类型 19:服务器响应和通知
- AMF3 编码:紧凑高效的二进制格式
命令类型:
| 命令名称 | 方向 | 描述 | 参数示例 |
|---|---|---|---|
| connect | C→S | 客户端连接到服务器 | app: 应用名, flashVer: 客户端版本, tcUrl: 服务器URL等 |
| disconnect | C→S | 客户端断开连接 | 无 |
| createStream | C→S | 客户端请求创建一个流 | 无 |
| deleteStream | C→S | 客户端删除一个流 | streamId: 流ID |
| play | C→S | 客户端请求播放一个流 | streamName: 流名称, start: 开始时间, duration: 持续时间, reset: 是否重置 |
| play2 | C→S | 扩展播放命令,支持不同的播放参数 | parameters: 参数对象 |
| pause | C→S | 客户端暂停或恢复播放 | pause: 是否暂停, time: 暂停的时间点 |
| seek | C→S | 客户端定位到指定时间 | offset: 时间偏移量 |
| publish | C→S | 客户端发布一个流 | streamName: 流名称, type: 发布类型(live, record, append) |
| closeStream | C→S | 客户端关闭流 | 无 |
| receiveAudio | C→S | 客户端通知服务器是否接收音频 | bool: 是否接收 |
| receiveVideo | C→S | 客户端通知服务器是否接收视频 | bool: 是否接收 |
| getStreamLength | C→S | 客户端获取流的长度 | streamName: 流名称 |
| FCPublish | C→S | 由Flash Media Server定义,开始发布流 | streamName: 流名称 |
| FCUnpublish | C→S | 由Flash Media Server定义,停止发布流 | streamName: 流名称 |
| releaseStream | C→S | 客户端释放流 | streamName: 流名称 |
| _result | S→C | 服务器对客户端命令的成功响应 | 命令的返回值,例如createStream返回流ID |
| _error | S→C | 服务器对客户端命令的错误响应 | 错误信息 |
| onStatus | S→C | 服务器通知客户端状态变化 | info: 包含level, code, description等状态信息 |
| onMetaData | S→C | 服务器发送流的元数据 | 包含视频宽度、高度、帧率等 |
| onFI | S→C | 服务器发送文件信息(用于文件播放) | 文件信息 |
| onBWDone | S→C | 服务器通知客户端带宽检测完成 | bandwidth: 带宽值 |
| checkBandwidth | S→C | 服务器通知客户端开始带宽检测 | 无 |
| getBandwidth | S→C | 服务器请求客户端报告带宽 | 无 |
| sampleAccess | S→C | 服务器通知客户端是否允许采样音频和视频 | audio: 是否允许音频采样, video: 是否允许视频采样 |
| setDataFrame | C→S | 客户端设置数据帧(用于发送元数据) | 元数据对象 |
| ping | S↔C | 心跳检测(Adobe的私有命令) | timestamp: 时间戳 |
| pong | S↔C | 心跳响应(Adobe的私有命令) | timestamp: 时间戳 |
| call | S↔C | 自定义命令 | 任意自定义数据 |
流程:
sequenceDiagram
participant C as Client
participant S as Server
C->>S: connect (类型17)
S->>C: Window Acknowledgement Size
S->>C: Set Peer Bandwidth
S->>C: onBWDone (类型19)
S->>C: _result (类型19) for connect
C->>S: createStream (类型17)
S->>C: _result (类型19) with stream ID
C->>S: play (类型17)
S->>C: onStatus (类型19) NetStream.Play.Start
S->>C: |音视频数据|
C->>S: onStatus (类型19) NetStream.Play.Stop
+----------------+----------------+----------------+----------------+
| 命令名称 | 事务ID | 参数对象 | 可选参数 |
| (String) | (Number) | (Object) | (Object) |
+----------------+----------------+----------------+----------------+
| "connect" | 1 | { | { |
| | | "app": str, | "fpad": bool|
| | | "tcUrl": str,| "capabilities": int|
| | | "flashVer": str| ... |
| | | } | } |
+----------------+----------------+----------------+----------------+
响应:
+----------------+----------------+----------------+----------------+
| 命令名称 | 事务ID | 连接属性 | 信息对象 |
| (String) | (Number) | (Object) | (Object) |
+----------------+----------------+----------------+----------------+
| "_result" | 1 | { | { |
| | | "fmsVer": str,| "level": "status"|
| | | "capabilities": int| "code": "NetConnection.Connect.Success"|
| | | } | "description": str|
| | | | "objectEncoding": int|
| | | | } |
+----------------+----------------+----------------+----------------+
+----------------+----------------+----------------+----------------+
| 命令名称 | 事务ID | 参数1 | 参数N |
| (String) | (Number) | (Any) | (Any) |
+----------------+----------------+----------------+----------------+
| "myMethod" | 123 | "param1" | 42 |
+----------------+----------------+----------------+----------------+
响应:
+----------------+----------------+----------------+----------------+
| 命令名称 | 事务ID | 结果 | |
| (String) | (Number) | (Any) | |
+----------------+----------------+----------------+----------------+
| "_result" | 123 | "success" | |
+----------------+----------------+----------------+----------------+
+----------------+----------------+----------------+
| 命令名称 | 事务ID | 保留参数 |
| (String) | (Number) | (Null) |
+----------------+----------------+----------------+
| "createStream"| 事务ID | null |
+----------------+----------------+----------------+
响应:
+----------------+----------------+----------------+----------------+
| 命令名称 | 事务ID | 保留参数 | 流ID |
| (String) | (Number) | (Null) | (Number) |
+----------------+----------------+----------------+----------------+
| "_result" | 事务ID | null | 流ID值 |
+----------------+----------------+----------------+----------------+
+----------------+----------------+----------------+----------------+
| 命令名称 | 事务ID | 保留参数 | 流名称 |
| (String) | (Number) | (Null) | (String) |
+----------------+----------------+----------------+----------------+
| "play" | 0 | null | "streamName" |
+----------------+----------------+----------------+----------------+
| 开始时间 | 持续时间 | 重置标志 |
| (Number) | (Number) | (Boolean) |
+----------------+----------------+----------------+
| -2 | -1 | true |
+----------------+----------------+----------------+
响应:
+----------------+----------------+----------------+----------------+
| 命令名称 | 事务ID | 保留参数 | 信息对象 |
| (String) | (Number) | (Null) | (Object) |
+----------------+----------------+----------------+----------------+
| "onStatus" | 0 | null | { |
| | | | "level": "status", |
| | | | "code": "NetStream.Play.Start", |
| | | | "description": "Playing liveStream" |
| | | | } |
+----------------+----------------+----------------+----------------+
+----------------+----------------+----------------+----------------+
| 命令名称 | 事务ID | 命令对象 | 流ID |
| (String) | (Number) | (Null) | (Number) |
+----------------+----------------+----------------+----------------+
| "deleteStream"| 事务ID | null | 流ID |
+----------------+----------------+----------------+----------------+
响应:
+----------------+----------------+----------------+----------------+
| 命令名称 | 事务ID | 命令对象 | 结果对象 |
| (String) | (Number) | (Null) | (Object) |
+----------------+----------------+----------------+----------------+
| "_result" | 5 | null | {} |
+----------------+----------------+----------------+----------------+
+----------------+----------------+----------------+----------------+----------------+
| 命令名称 | 事务ID | 流名称 | 时间偏移 | 可选参数 |
| (String) | (Number) | (String) | (Number) | (Boolean) |
+----------------+----------------+----------------+----------------+----------------+
| "seek" | 0 | "stream1" | 10000 | true |
+----------------+----------------+----------------+----------------+----------------+
响应:
+----------------+----------------+----------------+----------------+
| 命令名称 | 事务ID | 保留参数 | 状态对象 |
| (String) | (Number) | (Null) | (Object) |
+----------------+----------------+----------------+----------------+
| "onStatus" | 0 | null | { |
| | | | "level": "status", |
| | | | "code": "NetStream.Seek.Notify", |
| | | | "description": "Seek to 10000ms" |
| | | | } |
+----------------+----------------+----------------+----------------+
+----------------+----------------+----------------+----------------+----------------+
| 命令名称 | 事务ID | 保留参数 | 暂停标志 | 暂停位置 |
| (String) | (Number) | (Null) | (Boolean) | (Number) |
+----------------+----------------+----------------+----------------+----------------+
| "pause" | 0 | null | true | -2000 |
+----------------+----------------+----------------+----------------+----------------+
响应:
+----------------+----------------+----------------+----------------+
| 命令名称 | 事务ID | 保留参数 | 状态对象 |
| (String) | (Number) | (Null) | (Object) |
+----------------+----------------+----------------+----------------+
| "onStatus" | 0 | null | { |
| | | | "level": "status", |
| | | | "code": "NetStream.Pause.Notify", |
| | | | "description": "Paused stream" |
| | | | } |
+----------------+----------------+----------------+----------------+