SRS 代码分析【RTMP握手实现】
来源:互联网 发布:js设置placeholder颜色 编辑:程序博客网 时间:2024/06/08 01:20
RTMP简单握手实现
1.客户端握手的代码如下:
int SrsSimpleHandshake::handshake_with_server(SrsHandshakeBytes* hs_bytes, ISrsProtocolReaderWriter* io){ int ret = ERROR_SUCCESS; ssize_t nsize; // simple handshake if ((ret = hs_bytes->create_c0c1()) != ERROR_SUCCESS) { return ret; } if ((ret = io->write(hs_bytes->c0c1, 1537, &nsize)) != ERROR_SUCCESS) { srs_warn("write c0c1 failed. ret=%d", ret); return ret; } srs_verbose("write c0c1 success."); if ((ret = hs_bytes->read_s0s1s2(io)) != ERROR_SUCCESS) { return ret; } // plain text required. if (hs_bytes->s0s1s2[0] != 0x03) { ret = ERROR_RTMP_HANDSHAKE; srs_warn("handshake failed, plain text required. ret=%d", ret); return ret; } if ((ret = hs_bytes->create_c2()) != ERROR_SUCCESS) { return ret; } // for simple handshake, copy s1 to c2. // @see https://github.com/ossrs/srs/issues/418 memcpy(hs_bytes->c2, hs_bytes->s0s1s2 + 1, 1536); if ((ret = io->write(hs_bytes->c2, 1536, &nsize)) != ERROR_SUCCESS) { srs_warn("simple handshake write c2 failed. ret=%d", ret); return ret; } srs_verbose("simple handshake write c2 success."); srs_trace("simple handshake success."); return ret;}1).调用hs_bytes->create_c0c1()创建c0c1,并发送c0c1给服务端
int SrsHandshakeBytes::create_c0c1(){ int ret = ERROR_SUCCESS; if (c0c1) { return ret; } c0c1 = new char[1537]; srs_random_generate(c0c1, 1537); // plain text required. SrsBuffer stream; if ((ret = stream.initialize(c0c1, 9)) != ERROR_SUCCESS) { return ret; } stream.write_1bytes(0x03); stream.write_4bytes((int32_t)::time(NULL)); stream.write_4bytes(0x00); return ret;}
2).客户端调用hs_bytes->read_s0s1s2(io)等待读取服务端发送来的s0s1s2
3).客户端读取完s0s1s2后,接着调用hs_bytes->create_c2创建c2,c2的第二个时间是从s1中拷贝的,创建完成后会发送c2给服务端
int SrsHandshakeBytes::create_c2(){ int ret = ERROR_SUCCESS; if (c2) { return ret; } c2 = new char[1536]; srs_random_generate(c2, 1536); // time SrsBuffer stream; if ((ret = stream.initialize(c2, 8)) != ERROR_SUCCESS) { return ret; } stream.write_4bytes((int32_t)::time(NULL)); // c2 time2 copy from s1 if (s0s1s2) { stream.write_bytes(s0s1s2 + 1, 4); } return ret;}
int SrsSimpleHandshake::handshake_with_client(SrsHandshakeBytes* hs_bytes, ISrsProtocolReaderWriter* io){ int ret = ERROR_SUCCESS; ssize_t nsize; if ((ret = hs_bytes->read_c0c1(io)) != ERROR_SUCCESS) { return ret; } // plain text required. if (hs_bytes->c0c1[0] != 0x03) { ret = ERROR_RTMP_PLAIN_REQUIRED; srs_warn("only support rtmp plain text. ret=%d", ret); return ret; } srs_verbose("check c0 success, required plain text."); if ((ret = hs_bytes->create_s0s1s2(hs_bytes->c0c1 + 1)) != ERROR_SUCCESS) { return ret; } if ((ret = io->write(hs_bytes->s0s1s2, 3073, &nsize)) != ERROR_SUCCESS) { srs_warn("simple handshake send s0s1s2 failed. ret=%d", ret); return ret; } srs_verbose("simple handshake send s0s1s2 success."); if ((ret = hs_bytes->read_c2(io)) != ERROR_SUCCESS) { return ret; } srs_trace("simple handshake success."); return ret;}1).调用hs_bytes->read_c0c1(io)等待读取客户端发送来的c0,c1。
2).服务端读取c0c1后,会调用hs_bytes->create_s0s1s2创建s0s1s2。
其中s1的第二个时间是从c1中拷贝的,s2是直接拷贝的c1。
s0s1s2创建完成后会发送给客户端。
int SrsHandshakeBytes::create_s0s1s2(const char* c1){ int ret = ERROR_SUCCESS; if (s0s1s2) { return ret; } s0s1s2 = new char[3073]; srs_random_generate(s0s1s2, 3073); // plain text required. SrsBuffer stream; if ((ret = stream.initialize(s0s1s2, 9)) != ERROR_SUCCESS) { return ret; } stream.write_1bytes(0x03); stream.write_4bytes((int32_t)::time(NULL)); // s1 time2 copy from c1 if (c0c1) { stream.write_bytes(c0c1 + 1, 4); } // if c1 specified, copy c1 to s2. // @see: https://github.com/ossrs/srs/issues/46 if (c1) { memcpy(s0s1s2 + 1537, c1, 1536); } return ret;}3).服务端调用hs_bytes->read_c2(io)等待读取客户端发送来的c2
包结构说明
c0 s0包结构:
只有8个bit占用1字节,双方通过这个命令来同步版本号,现在版本是03.
c1 s1包结构
这两个包第一个time是双方各自发出的time,c1包zero的4个字节都为0,s1 包中zero的四个字节使用从c1中获取的time。
c2 s2包结构
c2,s2是有发送顺序的,必须是s2首先发出,然后c2才可以发出。
RTMP复杂握手说明
转载:http://blog.csdn.net/win_lin/article/details/13006803
当服务器和客户端的握手是按照rtmp协议进行,是不支持h264/aac的,有数据,就是没有视频和声音。
原因是adobe变更了握手的数据结构,标准rtmp协议的握手的包是随机的1536字节(S1S2C1C2),变更后的是需要进行摘要和加密。
rtmp协议定义的为simple handshake,变更后加密握手可称为complex handshake。
本文详细分析了rtmpd(ccrtmpserver)中的处理逻辑,以及rtmpdump的处理逻辑,从一个全是魔法数字的世界找到他们的数据结构和算法。
complex handshake C1S1结构
complex handshake将C1S1分为4个部分,它们的顺序(schema)一种可能是:
其中,key和digest可能会交换位置,即schema可能是:
客户端来决定使用哪种schema,服务器端则需要先尝试按照schema0解析,失败则用schema1解析。如下图所示:
无论key和digest位置如何,它们的结构是不变的:
备注:发现FMS只认识digest-key结构。
如下图所示:
crtmp中这些全是魔法数字。
complex handshake C2S2结构
C2S2主要是提供对C1S1的验证。结构如下:
C2S2的结构相对比较简单。如下图所示:
下面介绍C1S1C2S2的生成以及验证算法。
complex handshake C1S1算法
C1S1中都是包含32字节的digest,而且digest将C1S1分成两部分:
如下图所示:
在生成C1时,需要用到c1s1-part1和c1s1-part2这两个部分的字节拼接起来的字节,定义为:
也就是说,把1536字节的c1s1中的32字节的digest拿剪刀剪掉,剩下的头和尾加在一起就是c1s1-joined。
用到的两个常量FPKey和FMSKey:
生成C1的算法如下:
生成S1的算法如下:
C1S1的算法完毕。
complex handshake C2S2
C2S2的生成算法如下:
验证的算法是一样的。
- SRS 代码分析【RTMP握手实现】
- SRS 代码分析【RTMP连接请求响应】
- SRS 代码分析【RTMP信息play/publish】
- SRS 代码分析【RTMP Chunck数据读取】
- SRS 代码分析【RTMP Chunck数据发送】
- SRS 代码分析【HTTP-FLV传输实现】
- SRS 代码分析【转发流实现】
- SRS 代码分析【DVR录像实现】
- SRS 代码分析
- srs代码学习(8)--rtmp发送
- srs rtmp
- RTMP SRS源与边界的实现
- SRS 代码分析【服务器启动】
- SRS 代码分析【HLS切片】
- SRS(simple-rtmp-server)流媒体服务器源码分析--启动
- SRS(simple-rtmp-server)流媒体服务器源码分析--HLS切片
- SRS(simple-rtmp-server)流媒体服务器源码分析--启动
- srs之rtmp
- 命令行生成并直接运行jar包
- goto、迭代与循环控制
- 用数独游戏来解释循环关系网络(Recurrent Relation Networks)
- 迁移学习——机器学习的下一个前沿阵地
- 机器学习(2)——回归算法: 回归分析
- SRS 代码分析【RTMP握手实现】
- Spring Cloud构建微服务架构服务消费Ribbon
- 9种高性能可用高并发的技术架构
- 单击弹出一个dialog
- ycmd server SHUT DOWN
- NLP大神推荐的机器学习入门书单(附大量百度网盘电子书)
- maven中pom文件内Scope的作用
- SQL Server 动态行转列(参数化表名、分组列、行转列字段、字段值)
- Spring Cloud构建微服务架构服务消费Feign