小弟参照 rtmp协议的标准的握手部分大致这样的意思:
.Client → Server :向服务器发出握手请求.这不属于协议包一部分,该握手请求第一个字节为(0×03),其后跟着1536个字节.
.尽管看上去这部分的内容对于RTMP协议来说并不是至关重要的,但也不可随意对待.
.Server → Client :服务器向客户端回应握手请求.这部分的数据仍然不属于RTMP协议的部分.该回应的其实字节仍然为(0x03),
.但是后边跟着个长度为1536个字节(一共为3072 )的包块.第一个1536块看上去似乎可以是任意内容,甚至好像可以是Null都没有 关系.第二个1536的代码块,
.是上一步客户端向服务器端发送的握手请求的内容.
.Client→Server:把上一步服务器向客户端回应的第二块1536个字节的数据块.
但是小弟用red5自带的一个视频播发的例子通过wireshark捕获得到的握手的数据包不满足以上协议的说明,具体情况着这样的,
.其中c0为03;c1的time字段为 00 42 cb 18;zero 字段为 80 00 07 02;random(随机数为)为 5f 74 c4 77 ca 17 14...
.对应s0为03;s1的time字段为 00 00 00 00;zero 字段为 01 02 03 04;random(随机数据)为 9d 4e 94 d4 ca 6a 6b 63....
.s2的time为 44 b4 3a b9;time2为 94 b3 a6 c1; 随机返回为:a1 e7 ac a0 41 e5 df...
.c2的time为 00 00 00 00;time2为 00 00 00 00; 随机返回为:9d 4e 94 d4 ca 6a 6b 63...
.我发现一些问题 c2 的time对应着s1 的time, c2的随机返回对应着s1的随机数据,这个数据正常但是s2与c1几乎没有多大的联系
是不是red5的remp协议的处理有问题,还是rtmp协议更新了?
请各位前辈指点一二,谢谢!
------解决思路----------------------
给你一个建议:
(1)貌似你没有读它的协议,这东西不是猜是没用的。
(2)如果你连Handshake都看不懂的话,后面还有更复杂的概念,够你吃一壶的。所以你必须看明白它的文档,自己看明白。如果看不明白,就不要自己写这个协议了,用adobe自带的库吧。
------解决思路----------------------
RTMP这个协议虽然不能说烂,但也决非一流的协议。文档很乱,保持在draft水准,还是v1.0。
1. 你暂时不用关心这个timestamp,在写代码的时候总是设置为00 00 00 00即可
2. zero也设成为0就行了
3. 用wireshark高点的版本可以自动解析RTMP,方便跟踪,不要自己明码分析
4. 可以先用adobe的live encoder与fms交互,对其抓包分析,验证协议
你自己动手,handshake部分还很容易通过的。但是后面的事情估计对你来说有点复杂,它自己有复用层,还要编成AMF0格式的消息。从你目前的状况看,要完成一个RTMP要猴年马月了吧,呵呵
我写过一点文档,不过我不面向这么简单的问题的。
http://blog.sina.com.cn/s/articlelist_2365457685_2_1.html
------解决思路----------------------
// C0, C1, C2, S0, S1, S2
int RTMP_LiveConn::Handshake()
{
RTMP_UINT8 buf_C0[1];
RTMP_UINT8 buf_S0[1];
int n;
buf_C0[0] = RTMP_VERSION;
m_pLogger->Write(LOG_NORMAL,"Send C0.");
if(m_iSock.Send(buf_C0, 1) <0)
{
printf("failed to send C0.\n");
return -1;
}
// 起时时间
RTMP_UINT32 timestamp = 0;
m_iSysClock.Reset();
RTMP_UINT8 buf_C1[1536];
if(1)
{
RTMP_Encoder enc(buf_C1);
enc.PutUint32(timestamp);
enc.PutPadding(4, 0);
}
m_pLogger->Write(LOG_NORMAL,"Send C1.");
if(m_iSock.Send(buf_C1, 1536) <0)
{
printf("failed to send C1.\n");
return -1;
}
// 接收S0
m_pLogger->Write(LOG_NORMAL,"Recv S0.");
n = m_iSock.Recv(buf_S0,1);
if(n != 1)
{
printf("failed to recv S0.\n");
return -1;
}
if(buf_S0[0] != RTMP_VERSION)
{
printf("S0 error. \n");
return -1;
}
// 接收S1
m_pLogger->Write(LOG_NORMAL,"Recv S1.");
RTMP_UINT8 buf_S1[1536];
TryRecvAll(1536);
n = m_nBytesNum;
if(n != 1536)
{
printf("error: S1 length %d bytes.\n", n);
return -1;
}
memcpy(buf_S1, m_pBytes, n);
// 发送C2 (C2=S1)
RTMP_UINT8 buf_C2[1536];
memcpy(buf_C2, buf_S1, 1536);
if(1)
{
RTMP_Encoder enc(buf_C2);
enc.Skip(4);
// 计算时间
RTMP_UINT32 timestamp = m_iSysClock.Update();
enc.PutUint32(timestamp);
}
m_pLogger->Write(LOG_NORMAL,"Send C2.");
if(m_iSock.Send(buf_C2, 1536) < 0)
{
printf("failed to send C2.\n");
return -1;
}
// 接收S2 (SHOULD == C1)
m_pLogger->Write(LOG_NORMAL,"Recv S2.");
RTMP_UINT8 buf_S2[1536];
TryRecvAll(1536);
n = m_nBytesNum;
if(n != 1536)
{
printf("error: S2 length %d bytes.", n);
return -1;
}
memcpy(buf_S2, m_pBytes, n);
if(memcmp(buf_C1+8, buf_S2+8, 1528) != 0)
{
printf("S2 != C1 \n");
return -1;
}
timestamp = 0;
if(1)
{
RTMP_Decoder dec(buf_S2+4);
timestamp = dec.GetUint32();
printf("time delta = %d ms\n", timestamp);
}
return 0;
}