5.2 握手
一个RTMP连接以握手开始。这里的握手和其他协议的握手不同, 这里的握手由3个固定大小的块组成, 而不是可变大小的块加上头。
5.2.1 握手流程
握手由客户端发送 C0
和C1
块开始。
客户端必须等接收到S1
之后才可以发送C2
。
客户端必须等接收到S2
之后才可以发送其他数据。
服务器必须等接收到C0
之后才可以发送S0
和S1
, 也可能是接收到C1
之后发送。 服务器必须等接收到C1
之后才可以发送S2
。 服务器必须等接收到C2
之后才可以发送其他数据。
5.2.2 C0
和S0
格式
C0
和S0
是单独的一个字节, 可以当做一个8bit的整数字段来对待。
以下是CO
和S0
包的字段解释:
- 版本号(8位): 在
C0
包中, 该字段表示客户端请求的RTMP版本。 在S0
中, 该字段表示服务器选择的RTMP版本。 本规范所定义的版本是3
。 可选值中, 0-2是早期版本所用的, 已被丢弃; 4-31保留在未来使用; 32-255不允许使用(为了区分其他以某一可见字符开始的文本协议)。 如果服务器不能识别客户端请求的版本, 应该返回3
, 客户端可能选择降级到版本3
, 也可能放弃握手。
5.2.3 C1
和S1
格式
C1
和S1
包的长度固定为1536字节, 包含以下字段:
- 时间戳(4字节): 该字段承载一个时间戳, 该时间戳应该作为发送端点所有后续块的时间戳起始时间。 可以是0, 也可以是其他的任意值。 为了同步多个块流, 端点可能会发送其他块流时间戳的当前值。
- 零值(4字节): 该字段所有值都必须为0。
- 随机数据(1528字节): 该字段可以是任意值。 因为每个端点都需要区分自己和其他端点初始化的握手响应, 所以此数据应该有充分的随机性, 但是没必要使用加密安全的随机值或动态值。
5.2.4 C2
和S2
格式
C2
和S2
包的长度固定为1536字节, 基本上分别是S1
和C1
的回显, 包含以下字段:
- 时间戳(4字节): 该字段必须包含对等端发来的时间戳(对
C2
来说是S1
, 对S2
来说是C1
。 - 时间2(4字节): 该字段必须包含先前发送的并被对端读取的包的时间戳。(
C1
或S1
)。 - 随机数据回显(1528字节):该字段必须包含对端发送过来的随机数据字段值(对
C2
来说是S1
, 对S2
来说是C1
)。 任何一端都可以用时间戳和时间戳2两个字段值和当前时间戳来快速的估算带宽和延迟, 但这样可能并不实用。
5.2.5 握手流程示意图
下面是对图中提到的状态的解释:
- Uninitialized: 未初始化状态。 在该阶段发送协议版本, 客户端和服务端都未初始化。 客户端在
C0
包中发送RTMP协议版本, 如果服务器支持此版本, 服务器将在响应中发送S0
和S1
;如果不支持, 服务器采用适当的行为作为响应, 在RTMP规范中是终止连接。 - Version Send: 版本已发送状态。在未初始化状态之后客户端和服务端都进入版本已发送状态。 客户端等待接收
S1
包, 服务端等待接收C1
包。 收到所等待的包后, 客户端发送C2
包, 服务端发送S2
包。 之后状态进入发送确认状态。 - Ack Send: 客户端和服务端等待接收
S2
和C2
包, 收到后进入握手完成状态。 - Handshake Done: 握手完成, 客户端和服务端开始交换消息。