给你一个建议:
(1)貌似你没有读它的协议,这东西不是猜是没用的。
(2)如果你连Handshake都看不懂的话,后面还有更复杂的概念,够你吃一壶的。所以你必须看明白它的文档,自己看明白。如果看不明白,就不要自己写这个协议了,用adobe自带的库吧。

解决方案 »

  1.   

    Time: 4 bytes
    This field contains a timestamp, which SHOULD be used as the epoch
    for all future chunks sent from this endpoint. This may be 0, or
    some arbitrary value. To synchronize multiple chunkstreams, the
    endpoint may wish to send the current value of the other
    chunkstream's timestamp.Zero: 4 bytes
    This field MUST be all 0s.Random data: 1528 bytes
    This field can contain any arbitrary values. Since each endpoint
    has to distinguish between the response to the handshake it has
    initiated and the handshake initiated by its peer,this data SHOULD
    send something sufficiently random. But there is no need for
    cryptographically-secure randomness, or even dynamic values.
      

  2.   

    时间称为epoch,作为后续的时间基准
    随机字节用于确认正确性,越随机越好。在C1,S1, C2, S2中使用,C2=S1, C1=S2互相验证。
      

  3.   

    标准我大概看了一遍,标准中对C2,S2的随机数据是这样描述的:
    Random echo: 1528 bytes
    This field MUST contain the random data field sent by the peer in
    S1 (for C2) or S2 (for C1).
    Either peer can use the time and time2 fields together with the
    current timestamp as a quick estimate of the bandwidth and/or
    latency of the connection, but this is unlikely to be useful.
    我对它的理解是这样的:握手通过C1,C2,S1,S2 中的随机数据进行验证:C2==S1,S2==C1.
    是不是这样理解?
    为什么我捕到的数据包中C2==S1,但是S2!=C1呢?还有C1,S1 中的zero字段都不是全零,为什么?
    后来我看了看red5的源代码S1中的zero字段确实为:01 02 03 04.代码如下:
    @Override
    protected void createHandshakeBytes() 
    {
       handshakeBytes = new byte[Constants.HANDSHAKE_SIZE];
      //timestamp
      handshakeBytes[0] = 0;
      handshakeBytes[1] = 0;
      handshakeBytes[2] = 0;
      handshakeBytes[3] = 0;
      //version (0x01020304)
      handshakeBytes[4] = 1;
      handshakeBytes[5] = 2;
      handshakeBytes[6] = 3;
      handshakeBytes[7] = 4;
      //fill the rest with random bytes
      byte[] rndBytes = new byte[Constants.HANDSHAKE_SIZE - 8];
      random.nextBytes(rndBytes);
      //copy random bytes into our handshake array
     System.arraycopy(rndBytes, 0, handshakeBytes, 8, (Constants.HANDSHAKE_SIZE - 8));
    }
    请前辈指点?是不是我捕到的包有问题?
      

  4.   

    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
      

  5.   

    谢谢iamshaofa对我耐心认真的指导,在网上找到一篇blog如下:
    http://hi.baidu.com/homegy/item/76e9a52dc24915d50f37f9f8
    是不是他所说的那样?
      

  6.   


    // 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;
    }
      

  7.   

    那个iamshaofa同仁,说了半天,我觉得他没明白楼主想要的东西,反倒更多的是在炫耀
    如果知道的话,不妨多给人家些建议,不会的话,也不用在这儿顾左右而言他,除了误导,就是浪费自己的时间了