InputStream读取源中不存在的额外字节




我有一个Java服务器,它接收从客户端应用程序发送的RTMP数据包。服务器使用InputStream读取packet header,识别packet body有多大,然后使用该size创建byte array,然后从该array中的InputStream读取该body
问题是:接收的字节集被修改了-有必要的字节(存在于源中)与源数据包中不存在的额外字节(我通过WireShark查看源数据包的内容,并将它们与我在服务器上接收的字节进行比较)
这些额外的字节是0xc6字节,顺便说一下
它看起来是这样的:
Source: ... 75 f1 f5 55 73 .... fc a9 47 14 ... 40 ca d5 75 ... fe 30 a7
Received: ... 75 f1 f5 55 73 c6 .... fc a9 47 14 c6 ... 40 ca d5 75 c6 ... fe 30 a7
...-表示"此处有一定数量的字节"
因此,我无法接收必要的数据,因为它被拉伸了,比我从rtmp header收到的body size要大。最重要的是,修改后的数据并不是我必须收到的
我的问题是:如何修复它?InputStream出了什么问题?为什么要将这些0xc6字节插入接收阵列
我知道我可以简单地解析接收到的数组并排除那些额外的字节,但这是一个糟糕的解决方案,因为速度和性能是必要的(在这种情况下,如果不比较整个数组,就不清楚它是额外的字节还是来自源的字节)。。。

enter code here
public static void getRtmpPacket(InputStream in) throws Exception {
    byte[] rtmpHeader = new byte[8];
    byte[] rtmpBody;
    int bodySize = 0;
    //reading rtmp header:
    in.read(rtmpHeader);
    //reading the body size. This method works fine
    bodySize = Server.bigEndianBytesToInt(rtmpHeader, 4, 3);
    rtmpBody = new byte[bodySize];
    in.read(rtmpBody);
    //printing received data:
    System.out.println("Packet:");
    System.out.println("Body size: " + bodySize);
    System.out.print(bytesToString(rtmpHeader) + " ");
    System.out.print(bytesToString(rtmpBody));
    System.out.println();
}

根据RTMP规范,它的行为正常。您需要"取消查询"传入的数据,因此在单个read()中一次性读取所有数据将不起作用。

沿着这些线的东西(伪代码):

int remaining = payloadSize;
int totalRead = 0;
int totalReadForChunk = 0;
while (true) {
  int num = read(buf, 0, min(remaining, chunkSize - totalReadForChunk))
  if (num < 0) break;  // i/o error
  appendData(<buf>, 0, num)
  totalReadForChunk += num
  remaining -= num
  if (remaining == 0) break;  // end of payload
  if (totalReadForChunk == chunkSize) {
     totalReadForChunk = 0;
     // read the chunk header (it's not neccessarily 0xc6)
     int header = read()
     if (header != currentStreamEmptyHeader) {  // 0xc6
       // ... parse the new rtmp message according to header value
       // (usually invoke the upper-level message reading method "recursively")
     }
  }
}

也许,您应该看到(并使用)Red5 Media Server和其他实现RTMP协议的开源解决方案的代码。

InputStream。read(byte[])只保证读取一个字节,并且它将长度作为实际读取长度的int返回。

in.read(rtmpHeader); // might read 1, 2, 3, .. 8 bytes.
//reading the body size. This method works fine
bodySize = Server.bigEndianBytesToInt(rtmpHeader, 4, 3);
rtmpBody = new byte[bodySize];
in.read(rtmpBody); // might read 1, 2, 3, ... bodySize bytes.

如果您不检查实际长度,并假设byte[]已满,那么在调用read()之前,您将获得任何字节。

使用DataInputStream 可以获得您想要的内容

DataInputStream dis = new DataInputStream(in);
int len = dis.readInt(); // read an int in big endian.
byte[]] bytes = new byte[len];
dis.readFully(bytes); // read the whole byte[] or throw an IOException.

问题已解决
这些额外的0xc6字节是RTMP数据包的分块字节,从WireShark中看不到
除此之外,收到的标题显示实际体型,WireShark"确认"了这一点,但事实上体型会更大,应该进行计算。

  • https://www.wireshark.org/lists/wireshark-bugs/200801/msg00011.html
  • http://red5.osflash.narkive.com/LYumrzr4/rtmp-video-packets-and-streaming-thereof#post12

相关内容

  • 没有找到相关文章

最新更新