RTMP握手协议

作者原创,转载请联系作者

RTMP简介

Real Time Messaging Protocol(实时消息传送协议协议)是Adobe Systems公司为Flash Player和服务器之间音频,视频和数据传输开发的私有协议,adobe目前提供了一个并不完整的rtmp specification给大众使用,所以在使用rtmp协议时需要按flash player返回的包进行解析.
目前rtmp有以下几个变种:

  • rtmp是工作在TCP之上的明文协议,默认使用1935端口
  • rtmps是rtmp使用TLS/SSL连接
  • rtmpe是adobe使用自己的加密机制对rtmp进行加密的,虽然加密机制是使用了行业标准,并且内部实现也是专有的,但rtmpe设计基本上错误的,它本身也不提供任何的安全性.
  • rtmpt是对rtmp协议提供了一个http的封装,主要是为了防止防火墙对其进行拦截.
包结构

rtmp消息包使用的是二进制数据流,它们使用AMF0/AMF3进行编码.与其它协议一样,rtmp消息也是也包括消息头与消息体,而消息头又可以分为basic header,chunk header,timestamp.

  • basic header是此包的唯一不变的部分,并且由一个独立的byte构成,这其中包括了2个作重要的标志位
  • chunk type以及stream id.chunk type决定了消息头的编码格式,该字段的长度完全依赖于stream id,stream id是一个可变长的字段.
  • message header该字段包含了将要发送的消息的信息(或者是一部分,一个消息拆成多个chunk的情况下是一部分)该字段的长度由chunk basic header中的trunk type决定.
  • timestamp扩展时间戳就比较好理解的,就是当chunk message header的时间戳大于等于0xffffff的时候chunk message header后面的四个字节就代表扩展时间.

握手协议

在rtmp连接建立后,服务端与客户端需要通过3次交换报文完成握手.
握手其他的协议不同,是由三个静态大小的块,而不是可变大小的块组成的,客户端与服务器发送相同的三个chunk,客户端发送c0,c1,c2 chunk,服务端发送s0,s1,s2 chunk.
-发送顺序
握手开始时,客户端将发送c0,c1 chunk,此时客户端必须等待,直到收到s1 chunk,才能发送c2 chunk.
此时服务端必须等待,直到已收到c0后才能发送s0和s1,当然也可能会等到接收c1后才发送.
当服务器收到c2后才能再发送的其他数据,同理,当客户端收到s2后才能发送其它数据.

  • 握手包格式
  1. c0与s0格式


    c0和s0包是一个1字节,可以看作是一个byte
    目前rtmp版本定义为3,0-2是早期的专利产品所使用的值,现已经废弃,4-31是预留值,32-255是禁用值(这样做是为了区分基于文本的协议,因为这些协议通常都是以一个可打印的字符开始),如果服务端不能识别客户请求的版本,那么它应该发送3的响应,客户端这时可以选择下降到版本3,也可以放弃这次握手.

  2. c1与s1格式


    c1与s1长度为1536个字节,它们由以下字段组成
    时间戳:该字段占4字节,包含了一个时间戳,它是所有从这个端点发送出去的将来数据块的起始点,它可以是零,或是任意值,为了同步多个数据块流,端点可能会将这个字段设成其它数据块流时间戳的当前值.
    0:此标记位占4字节,并且必须是0
    随机数:该字段占1528字节,可以是任意值,因为每个端点必须区分已经初始化的握手和对等端点初始化的握手的响应,所以这个数据要足够的随机,当然这个也不需要密码级的随机或是动态值.

  3. c2与s2格式


    c2和s2包长都是1536字节,几乎是s1和c1的回显.
    time1:该字段占4字节,包含有对方发送过来s1或c1的时间戳
    time2:该字段占4字节,包含有对方发送过来的前一个包(s1或者c1)的时间戳
    随机数回显:该字段占1528字节,包含有对方发送过来的随机数据字段,每个通信端点可以使用time和time2字段,以及当前的时间戳,来快速估计带宽和/或连接延时,但这个数值基本上没法用.

  • 握手状态


    1)未初始化:在这个阶段,协议版本被发送,客户和服务端都是未初始化的,客户端在包c1中发送协议版本,如果服务端支持这个版本,它将会发送s0和s1作为响应,如果不支持,则服务端会用相应的动作来响应,在RTMP中这个动作是结束这个连接.

  1. 版本发送完成:客户端和服务端在未初始化状态之后都进入到版本发送完成状态,客户端等待包s1,而服务端等待包c1,在收到相应的包后,客户端发送包c2,而服务端发磅包s2,状态变成询问发送完成.
  2. 询问发送完成:客户端和服务端等待s2和c2.
  3. 握手完成:客户端和服务端开始交换消息.

代码示例

  • 注册回调,设置初始态,等待接受客户端握手消息
    void ngx_rtmp_handshake(ngx_rtmp_session_t *s)
    {
    ngx_connection_t *c;
    c = s->connection;
    c->read->handler = ngx_rtmp_handshake_recv;
    c->write->handler = ngx_rtmp_handshake_send;
    s->hs_buf = ngx_rtmp_alloc_handshake_buffer(s);
    s->hs_stage = NGX_RTMP_HANDSHAKE_SERVER_RECV_CHALLENGE;
    ngx_rtmp_handshake_recv(c->read);
    }

  • 收到握手消息处理
    ++s->hs_stage;
    switch (s->hs_stage) {
    case NGX_RTMP_HANDSHAKE_SERVER_SEND_CHALLENGE:
    if (ngx_rtmp_handshake_parse_challenge(s,
    &ngx_rtmp_client_partial_key,
    &ngx_rtmp_server_full_key) != NGX_OK)
    {
    ngx_rtmp_finalize_session(s);
    return;
    }
    if (s->hs_old) {
    s->hs_buf->pos = s->hs_buf->start;
    s->hs_buf->last = s->hs_buf->end;
    } else if (ngx_rtmp_handshake_create_challenge(s,
    ngx_rtmp_server_version,
    &ngx_rtmp_server_partial_key) != NGX_OK)
    {
    ngx_rtmp_finalize_session(s);
    return;
    }
    ngx_rtmp_handshake_send(c->write);
    break;

      case NGX_RTMP_HANDSHAKE_SERVER_DONE:
          ngx_rtmp_handshake_done(s);
          break;
    
      case NGX_RTMP_HANDSHAKE_CLIENT_RECV_RESPONSE:
          if (ngx_rtmp_handshake_parse_challenge(s,
                  &ngx_rtmp_server_partial_key,
                  &ngx_rtmp_client_full_key) != NGX_OK)
          {
              ngx_rtmp_finalize_session(s);
              return;
          }
          s->hs_buf->pos = s->hs_buf->last = s->hs_buf->start + 1;
          ngx_rtmp_handshake_recv(c->read);
          break;
    
      case NGX_RTMP_HANDSHAKE_CLIENT_SEND_RESPONSE:
          if (ngx_rtmp_handshake_create_response(s) != NGX_OK) {
              ngx_rtmp_finalize_session(s);
              return;
          }
          ngx_rtmp_handshake_send(c->write);
          break;
      }
    
  • 握手完成处理
    static void ngx_rtmp_handshake_done(ngx_rtmp_session_t *s)
    {
    ngx_rtmp_free_handshake_buffers(s);
    if (ngx_rtmp_fire_event(s, NGX_RTMP_HANDSHAKE_DONE,
    NULL, NULL) != NGX_OK)
    {
    ngx_rtmp_finalize_session(s);
    return;
    }
    ngx_rtmp_cycle(s);
    }

其中处理NGX_RTMP_HANDSHAKE_DONE的回调如前文所ngx_rtmp_relay_module模块中注册的回调:ngx_rtmp_relay_handshake_done。其主要做三部分工作:
1)将自己的chunk发送给对方:ngx_rtmp_send_chunk_size
2)将ack_size发送给对方:ngx_rtmp_send_ack_size
3)将amf发送给对方:ngx_rtmp_send_amf,主要是:

{ NGX_RTMP_AMF_STRING, ngx_null_string, "connect", 0 },

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 200,612评论 5 471
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 84,345评论 2 377
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 147,625评论 0 332
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,022评论 1 272
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,974评论 5 360
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,227评论 1 277
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,688评论 3 392
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,358评论 0 255
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,490评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,402评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,446评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,126评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,721评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,802评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,013评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,504评论 2 346
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,080评论 2 341

推荐阅读更多精彩内容