rtmp学习-handshake

最近在学习OBS开源项目,借此学习流媒体方面的知识。

1)简介

rtmp 是Adobe公司为FLASH和服务器之间传输音视频数据开发的一种数据。基于TCP协议,使用1935默认端口。

2)一个RTMP连接已握手开始,握手以三个固定大小的块组成chunk[0]1字节,chunk[1]1536字节chunk[2]1536字节。客户端和服务端各自发送三个相同的块。client:c0,c1,c2;server:s0,s1,s2。

3)发送规则

1,握手开始于client发送c0,c1;

2,client在发送c2前必须等待接收s1;

3,client 在发送任何数据之前必须等待接收s2;

4,server在发送s0和s1之前必须等待接收c0,也可以等待接收c1;

5,server在发送s2前必须等待接收c1;

6,server在发送任何数据之前必须等待接收c2;

4)数据格式

C0或S0

C0和S0的长度是一个字节,

在 S0 中这个字段表示服务器选择的 RTMP 版本。

rtmp1.0规范所定义的版本是 3;0-2 是早期产品所用的,已被丢弃;4-31保留在未来使用;32-255 不允许使用(为了区分其他以某一字符开始的文本协议)。

如果服务无法识别客户端请求的版本,应该返回 3 。客户端可以选择减到版本 3 或选择取消握手。

C1或S1

C1 和 S1 有 1536 字节长,由下列字段组成

  • 时间:4 字节 本字段包含时间戳。该时间戳应该是发送这个数据块的端点的后续块的时间起始点。可以是 0,或其他的 任何值。为了同步多个流,端点可能发送其块流的当前值。
  • 零:4 字节 本字段必须是全零。
  • 随机数据:1528 字节。 本字段可以包含任何值。 因为每个端点必须用自己初始化的握手和对端初始化的握 手来区分身份,所以这个数据应有充分的随机性。但是并不需要加密安全的随机值,或者动态值
  • C2或S2

    C2 和 S2 消息有 1536 字节长。只是 S1 和 C1 的回复。本消息由下列字段组成。

  • 时间:4 字节 本字段必须包含对等段发送的时间(对 C2 来说是 S1,对 S2 来说是 C1)。

  • 时间 2:4 字节 本字段必须包含先前发送的并被对端读取的包的时间戳。

  • 随机回复:1528 字节 本字段必须包含对端发送的随机数据字段(对 C2 来说是 S1,对 S2 来说是 C1) 。 每个对等端可以用时间和时间 2 字段中的时间戳来快速地估计带宽和延迟。 但这样做可 能并不实用。

static int
HandShake(RTMP *r, int FP9HandShake)
{
    int i;
    uint32_t uptime, suptime;
    int bMatch;
    char type;

//RTMP_SIG_SIZE:1536,c1,c2长度;clientsig 指向了clientbuf数组的下表1开始的位置即C1的头
    char clientbuf[RTMP_SIG_SIZE + 1], *clientsig = clientbuf + 1;

    char serversig[RTMP_SIG_SIZE];

// "clientbuf的长度刚好是1536+1,此处第一个字节因为是0x03" 

// "这是rtmp规范中定义的客户端要求使用的rtmp版本,即C0"

    clientbuf[0] = 0x03; /* not encrypted */

//RTMP_GetTime()是用sysconf(_SC_CLK_TCK)函数获取系统clock的再处理(linux下)之后转化网络字节序作为C1的时间戳"  
    uptime = htonl(RTMP_GetTime())

 //"void *memcpy(void *dest, const void *src, int n) 将时间戳填到clientsig前四个字节中 (C1)"  

    memcpy(clientsig, &uptime, 4);

//"将clientsig中4~7字节置为0 (C1)"  

    memset(&clientsig[4], 0, 4);

//"给clientsig中后面 1528 个字节填上随机数(C1)"  
#ifdef _DEBUG
    for (i = 8; i < RTMP_SIG_SIZE; i++)
        clientsig[i] = 0xff;
#else
    for (i = 8; i < RTMP_SIG_SIZE; i++)
        clientsig[i] = (char)(rand() % 256);
#endif

//"发送clientbuf共1537字节(C0+C1)到服务器" 
    if (!WriteN(r, clientbuf, RTMP_SIG_SIZE + 1))
        return FALSE;

//"从服务器接受了一个字节即S0,并检查版本"  

    if (ReadN(r, &type, 1) != 1) /* 0x03 or 0x06 */
        return FALSE;


    RTMP_Log(RTMP_LOGDEBUG, "%s: Type Answer   : %02X", __FUNCTION__, type);

 //"若S0没问题的话,继续接受服务器的S1"  
    if (type != clientbuf[0])
        RTMP_Log(RTMP_LOGWARNING, "%s: Type mismatch: client sent %d, server answered %d",
                 __FUNCTION__, clientbuf[0], type);


    if (ReadN(r, serversig, RTMP_SIG_SIZE) != RTMP_SIG_SIZE)
        return FALSE;


    /* decode server response */

//以下一段是保存服务器的S1然后把服务器的S1作为客户端的C2发送给服务器"
    memcpy(&suptime, serversig, 4);
    suptime = ntohl(suptime);


    RTMP_Log(RTMP_LOGDEBUG, "%s: Server Uptime : %d", __FUNCTION__, suptime);
    RTMP_Log(RTMP_LOGDEBUG, "%s: FMS Version   : %d.%d.%d.%d", __FUNCTION__,
             serversig[4], serversig[5], serversig[6], serversig[7]);


    /* 2nd part of handshake */
    if (!WriteN(r, serversig, RTMP_SIG_SIZE))
        return FALSE;

//"接受服务器的S2"  
    if (ReadN(r, serversig, RTMP_SIG_SIZE) != RTMP_SIG_SIZE)
        return FALSE;

//"比较服务器的S2是否跟客户端C1相同,若是,则握手成功"
    bMatch = (memcmp(serversig, clientsig, RTMP_SIG_SIZE) == 0);
    if (!bMatch)
    {
        RTMP_Log(RTMP_LOGWARNING, "%s, client signature does not match!", __FUNCTION__);
    }


    /* er, totally unused? */
    (void)FP9HandShake;
    return TRUE;
}





  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值