InputStream 读取源中不存在的额外字节
InputStream reads extra bytes which are not exist in source
我有 Java 服务器接收从客户端应用程序发送的 RTMP 数据包。服务器使用 InputStream
读取 packet header
,识别 packet body
有多大,然后用 size
创建 byte array
,然后读取 body
] 从 InputStream
中 array
.
问题是: 接收到的字节集被 修改了 - 有必要的字节(存在于源中)和额外的字节不存在存在于源数据包中(我通过 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
...
- 表示 "some quantity of bytes here"
结果,我无法接收到必要的数据,因为它被拉伸了,比我从 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();
}
您可能应该看到(并使用)Red5 Media Server 和其他实现 RTMP 协议的开源解决方案的代码。
InputStream.read(byte[]) 只保证读取一个字节,return 长度为实际读取长度的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 中看不到。
不仅如此,收到的header说的是实际的body size和WireShark "confirms"吧,但实际上body size会大一些,应该计算一下。
根据 RTMP 规范,它表现正常。您需要 "unchunk" 传入数据,因此在一次 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")
}
}
}
我有 Java 服务器接收从客户端应用程序发送的 RTMP 数据包。服务器使用 InputStream
读取 packet header
,识别 packet body
有多大,然后用 size
创建 byte array
,然后读取 body
] 从 InputStream
中 array
.
问题是: 接收到的字节集被 修改了 - 有必要的字节(存在于源中)和额外的字节不存在存在于源数据包中(我通过 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
...
- 表示 "some quantity of bytes here"
结果,我无法接收到必要的数据,因为它被拉伸了,比我从 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();
}
您可能应该看到(并使用)Red5 Media Server 和其他实现 RTMP 协议的开源解决方案的代码。
InputStream.read(byte[]) 只保证读取一个字节,return 长度为实际读取长度的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 中看不到。
不仅如此,收到的header说的是实际的body size和WireShark "confirms"吧,但实际上body size会大一些,应该计算一下。
根据 RTMP 规范,它表现正常。您需要 "unchunk" 传入数据,因此在一次 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")
}
}
}