一、原始版本
- DynamicLengthPacketHandler.java
java
public class DynamicLengthPacketHandler {
private byte[] buffer = new byte[0];
private int parseFlag = PARSE_FLAG_HEADER;
public static final int HEADER_LENGTH = 4;
private int bodyLength;
private static final int PARSE_FLAG_HEADER = 0;
private static final int PARSE_FLAG_BODY = 1;
public List<byte[]> handleData(byte[] data) {
byte[] newBuffer = new byte[buffer.length + data.length];
System.arraycopy(buffer, 0, newBuffer, 0, buffer.length);
System.arraycopy(data, 0, newBuffer, buffer.length, data.length);
buffer = newBuffer;
List<byte[]> completeResults = new ArrayList<>();
int position = 0;
while (true) {
if (parseFlag == PARSE_FLAG_HEADER) {
// 处理消息头,得到消息体长度
if (buffer.length - position < HEADER_LENGTH) {
break;
}
bodyLength = Byte.toUnsignedInt(buffer[position + 3]) |
(Byte.toUnsignedInt(buffer[position + 2]) << 8) |
(Byte.toUnsignedInt(buffer[position + 1]) << 16) |
(Byte.toUnsignedInt(buffer[position]) << 24);
position += HEADER_LENGTH;
parseFlag = PARSE_FLAG_BODY;
}
// 处理消息体
if (position + bodyLength > buffer.length) {
break;
}
byte[] completeResult = new byte[bodyLength];
System.arraycopy(buffer, position, completeResult, 0, bodyLength);
completeResults.add(completeResult);
position += bodyLength;
parseFlag = PARSE_FLAG_HEADER;
}
if (position > 0) {
byte[] remaining = new byte[buffer.length - position];
System.arraycopy(buffer, position, remaining, 0, remaining.length);
buffer = remaining;
}
return completeResults;
}
public void clear() {
buffer = new byte[0];
parseFlag = PARSE_FLAG_HEADER;
}
public static byte[] buildPacket(String data) {
byte[] body = data.getBytes();
byte[] packet = new byte[4 + body.length];
packet[0] = (byte) ((body.length >> 24) & 0xFF);
packet[1] = (byte) ((body.length >> 16) & 0xFF);
packet[2] = (byte) ((body.length >> 8) & 0xFF);
packet[3] = (byte) (body.length & 0xFF);
System.arraycopy(body, 0, packet, 4, body.length);
return packet;
}
}
- 原始版本对异常长度完全没有处理能力,异常的长度包括错误的长度值、过长的长度值
-
错误的长度值:直接采用读取到的任何长度值,一旦解析到错误长度就卡住,无法继续处理后续数据
-
过长的长度值:例如,如果读取到过长的长度值,会尝试分配过大内存,导致内存溢出
二、原始版本测试用例
- 遇到错误的长度值
java
byte[] someData1 = DynamicLengthPacketHandler.buildPacket("Hello");
byte[] someData2 = DynamicLengthPacketHandler.buildPacket("World");
byte[] someData3 = DynamicLengthPacketHandler.buildPacket("Java");
someData1[0] = (byte) 0x00;
someData1[1] = (byte) 0x00;
someData1[2] = (byte) 0x00;
someData1[3] = (byte) 0x07;
DynamicLengthPacketHandler handler = new DynamicLengthPacketHandler();
List<byte[]> results = handler.handleData(someData1);
System.out.println("第 1 次解析结果数量: " + results.size());
for (byte[] result : results) {
System.out.println("解析内容: " + new String(result));
}
results = handler.handleData(someData2);
System.out.println("第 2 次解析结果数量: " + results.size());
for (byte[] result : results) {
System.out.println("解析内容: " + new String(result));
}
results = handler.handleData(someData3);
System.out.println("第 3 次解析结果数量: " + results.size());
for (byte[] result : results) {
System.out.println("解析内容: " + new String(result));
}
# 输出结果
第 1 次解析结果数量: 0
第 2 次解析结果数量: 1
解析内容: Hello
第 3 次解析结果数量: 0
- 遇到过长的长度值
java
byte[] someData1 = DynamicLengthPacketHandler.buildPacket("Hello");
byte[] someData2 = DynamicLengthPacketHandler.buildPacket("World");
byte[] someData3 = DynamicLengthPacketHandler.buildPacket("Java");
someData1[0] = (byte) 0x0F;
someData1[1] = (byte) 0xFF;
someData1[2] = (byte) 0xFF;
someData1[3] = (byte) 0xFF;
DynamicLengthPacketHandler handler = new DynamicLengthPacketHandler();
List<byte[]> results = handler.handleData(someData1);
System.out.println("第 1 次解析结果数量: " + results.size());
for (byte[] result : results) {
System.out.println("解析内容: " + new String(result));
}
results = handler.handleData(someData2);
System.out.println("第 2 次解析结果数量: " + results.size());
for (byte[] result : results) {
System.out.println("解析内容: " + new String(result));
}
results = handler.handleData(someData3);
System.out.println("第 3 次解析结果数量: " + results.size());
for (byte[] result : results) {
System.out.println("解析内容: " + new String(result));
}
# 输出结果
第 1 次解析结果数量: 0
第 2 次解析结果数量: 0
第 3 次解析结果数量: 0
java
byte[] someData1 = DynamicLengthPacketHandler.buildPacket("Hello");
byte[] someData2 = DynamicLengthPacketHandler.buildPacket("World");
byte[] someData3 = DynamicLengthPacketHandler.buildPacket("Java");
someData1[0] = (byte) 0xFF;
someData1[1] = (byte) 0xFF;
someData1[2] = (byte) 0xFF;
someData1[3] = (byte) 0xFF;
DynamicLengthPacketHandler handler = new DynamicLengthPacketHandler();
List<byte[]> results = handler.handleData(someData1);
System.out.println("第 1 次解析结果数量: " + results.size());
for (byte[] result : results) {
System.out.println("解析内容: " + new String(result));
}
results = handler.handleData(someData2);
System.out.println("第 2 次解析结果数量: " + results.size());
for (byte[] result : results) {
System.out.println("解析内容: " + new String(result));
}
results = handler.handleData(someData3);
System.out.println("第 3 次解析结果数量: " + results.size());
for (byte[] result : results) {
System.out.println("解析内容: " + new String(result));
}
# 输出结果
Exception in thread "main" java.lang.NegativeArraySizeException: -1
三、优化版本
- DynamicLengthPacketHandler.java
java
public class DynamicLengthPacketHandler {
private byte[] buffer = new byte[0];
public static final int HEADER_LENGTH = 8;
private static final int MAGIC_NUMBER = 0x12345678;
private static final byte MAGIC_BYTE_1 = (byte) 0x12;
private static final byte MAGIC_BYTE_2 = (byte) 0x34;
private static final byte MAGIC_BYTE_3 = (byte) 0x56;
private static final byte MAGIC_BYTE_4 = (byte) 0x78;
private int bodyLength;
private static final int MAX_BODY_LENGTH = 20 * 1024 * 1024;
private static final int MIN_BODY_LENGTH = 0;
private int parseFlag = PARSE_FLAG_HEADER;
private static final int PARSE_FLAG_HEADER = 0;
private static final int PARSE_FLAG_BODY = 1;
public List<byte[]> handleData(byte[] data) {
byte[] newBuffer = new byte[buffer.length + data.length];
System.arraycopy(buffer, 0, newBuffer, 0, buffer.length);
System.arraycopy(data, 0, newBuffer, buffer.length, data.length);
buffer = newBuffer;
List<byte[]> completeResults = new ArrayList<>();
int position = 0;
while (true) {
if (parseFlag == PARSE_FLAG_HEADER) {
// 处理消息头
if (buffer.length - position < HEADER_LENGTH) {
break;
}
int magic = Byte.toUnsignedInt(buffer[position + 3]) |
(Byte.toUnsignedInt(buffer[position + 2]) << 8) |
(Byte.toUnsignedInt(buffer[position + 1]) << 16) |
(Byte.toUnsignedInt(buffer[position]) << 24);
if (magic != MAGIC_NUMBER) {
position++;
continue;
}
bodyLength = Byte.toUnsignedInt(buffer[position + 7]) |
(Byte.toUnsignedInt(buffer[position + 6]) << 8) |
(Byte.toUnsignedInt(buffer[position + 5]) << 16) |
(Byte.toUnsignedInt(buffer[position + 4]) << 24);
if (bodyLength < MIN_BODY_LENGTH || bodyLength > MAX_BODY_LENGTH) {
position++;
continue;
}
position += HEADER_LENGTH;
parseFlag = PARSE_FLAG_BODY;
}
// 处理消息体
if (position + bodyLength > buffer.length) {
break;
}
byte[] completeResult = new byte[bodyLength];
System.arraycopy(buffer, position, completeResult, 0, bodyLength);
completeResults.add(completeResult);
position += bodyLength;
parseFlag = PARSE_FLAG_HEADER;
}
if (position > 0) {
byte[] remaining = new byte[buffer.length - position];
System.arraycopy(buffer, position, remaining, 0, remaining.length);
buffer = remaining;
}
return completeResults;
}
public void clear() {
buffer = new byte[0];
parseFlag = PARSE_FLAG_HEADER;
}
public static byte[] buildPacket(String data) {
byte[] body = data.getBytes();
byte[] packet = new byte[HEADER_LENGTH + body.length];
// 设置魔数
packet[0] = MAGIC_BYTE_1;
packet[1] = MAGIC_BYTE_2;
packet[2] = MAGIC_BYTE_3;
packet[3] = MAGIC_BYTE_4;
// 设置消息头
packet[4] = (byte) ((body.length >> 24) & 0xFF);
packet[5] = (byte) ((body.length >> 16) & 0xFF);
packet[6] = (byte) ((body.length >> 8) & 0xFF);
packet[7] = (byte) (body.length & 0xFF);
// 设置消息体
System.arraycopy(body, 0, packet, HEADER_LENGTH, body.length);
return packet;
}
}
-
优化版本通过魔数验证,只有正确的协议头才会解析长度,过滤掉垃圾数据
-
同时设置
MAX_BODY_LENGTH = 20MB,拒绝处理过大的包
四、优化版本测试用例
- 遇到错误的长度值
java
byte[] someData1 = DynamicLengthPacketHandler.buildPacket("Hello");
byte[] someData2 = DynamicLengthPacketHandler.buildPacket("World");
byte[] someData3 = DynamicLengthPacketHandler.buildPacket("Java");
someData1[0] = (byte) 0x00;
someData1[1] = (byte) 0x00;
someData1[2] = (byte) 0x00;
someData1[3] = (byte) 0x07;
DynamicLengthPacketHandler handler = new DynamicLengthPacketHandler();
List<byte[]> results = handler.handleData(someData1);
System.out.println("第 1 次解析结果数量: " + results.size());
for (byte[] result : results) {
System.out.println("解析内容: " + new String(result));
}
results = handler.handleData(someData2);
System.out.println("第 2 次解析结果数量: " + results.size());
for (byte[] result : results) {
System.out.println("解析内容: " + new String(result));
}
results = handler.handleData(someData3);
System.out.println("第 3 次解析结果数量: " + results.size());
for (byte[] result : results) {
System.out.println("解析内容: " + new String(result));
}
# 输出结果
第 1 次解析结果数量: 0
第 2 次解析结果数量: 1
解析内容: World
第 3 次解析结果数量: 1
解析内容: Java
- 遇到过长的长度值
java
byte[] someData1 = DynamicLengthPacketHandler.buildPacket("Hello");
byte[] someData2 = DynamicLengthPacketHandler.buildPacket("World");
byte[] someData3 = DynamicLengthPacketHandler.buildPacket("Java");
someData1[0] = (byte) 0x0F;
someData1[1] = (byte) 0xFF;
someData1[2] = (byte) 0xFF;
someData1[3] = (byte) 0xFF;
DynamicLengthPacketHandler handler = new DynamicLengthPacketHandler();
List<byte[]> results = handler.handleData(someData1);
System.out.println("第 1 次解析结果数量: " + results.size());
for (byte[] result : results) {
System.out.println("解析内容: " + new String(result));
}
results = handler.handleData(someData2);
System.out.println("第 2 次解析结果数量: " + results.size());
for (byte[] result : results) {
System.out.println("解析内容: " + new String(result));
}
results = handler.handleData(someData3);
System.out.println("第 3 次解析结果数量: " + results.size());
for (byte[] result : results) {
System.out.println("解析内容: " + new String(result));
}
# 输出结果
第 1 次解析结果数量: 0
第 2 次解析结果数量: 1
解析内容: World
第 3 次解析结果数量: 1
解析内容: Java
java
byte[] someData1 = DynamicLengthPacketHandler.buildPacket("Hello");
byte[] someData2 = DynamicLengthPacketHandler.buildPacket("World");
byte[] someData3 = DynamicLengthPacketHandler.buildPacket("Java");
someData1[0] = (byte) 0xFF;
someData1[1] = (byte) 0xFF;
someData1[2] = (byte) 0xFF;
someData1[3] = (byte) 0xFF;
DynamicLengthPacketHandler handler = new DynamicLengthPacketHandler();
List<byte[]> results = handler.handleData(someData1);
System.out.println("第 1 次解析结果数量: " + results.size());
for (byte[] result : results) {
System.out.println("解析内容: " + new String(result));
}
results = handler.handleData(someData2);
System.out.println("第 2 次解析结果数量: " + results.size());
for (byte[] result : results) {
System.out.println("解析内容: " + new String(result));
}
results = handler.handleData(someData3);
System.out.println("第 3 次解析结果数量: " + results.size());
for (byte[] result : results) {
System.out.println("解析内容: " + new String(result));
}
# 输出结果
第 1 次解析结果数量: 0
第 2 次解析结果数量: 1
解析内容: World
第 3 次解析结果数量: 1
解析内容: Java