Java 开发 - 粘包处理器 - 基于消息头 + 消息体

具体实现

  • DynamicLengthPacketHandler.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;
    }
}

测试用例

  1. 单个完整数据包
byte[] packet = DynamicLengthPacketHandler.buildPacket("Hello");

DynamicLengthPacketHandler handler = new DynamicLengthPacketHandler();

List<byte[]> results = handler.handleData(packet);

System.out.println("解析结果数量: " + results.size());
for (byte[] result : results) {
    System.out.println("解析内容: " + new String(result));
}
# 输出结果

解析结果数量: 1
解析内容: Hello
  1. 多个完整数据包(粘包)
byte[] packet1 = DynamicLengthPacketHandler. buildPacket("Hello");
byte[] packet2 = DynamicLengthPacketHandler. buildPacket("World");
byte[] packet3 = DynamicLengthPacketHandler. buildPacket("Java");

byte[] combined = new byte[packet1.length + packet2.length + packet3.length];
System.arraycopy(packet1, 0, combined, 0, packet1.length);
System.arraycopy(packet2, 0, combined, packet1.length, packet2.length);
System.arraycopy(packet3, 0, combined, packet1.length + packet2.length, packet3.length);

DynamicLengthPacketHandler handler = new DynamicLengthPacketHandler();

List<byte[]> results = handler.handleData(combined);

System.out.println("解析结果数量: " + results.size());
for (byte[] result : results) {
    System.out.println("解析内容: " + new String(result));
}
# 输出结果

解析结果数量: 3
解析内容: Hello
解析内容: World
解析内容: Java
  1. 不完整数据包(半包)
byte[] fullPacket = DynamicLengthPacketHandler.buildPacket("HelloWorld");
byte[] partialData = new byte[8];
System.arraycopy(fullPacket, 0, partialData, 0, 8);

DynamicLengthPacketHandler handler = new DynamicLengthPacketHandler();

List<byte[]> results = handler.handleData(partialData);

System.out.println("解析结果数量: " + results.size());
for (byte[] result : results) {
    System.out.println("解析内容: " + new String(result));
}
# 输出结果

解析结果数量: 0
  1. 分包处理
byte[] fullPacket = DynamicLengthPacketHandler.buildPacket("HelloWorldJava");

byte[] part1 = new byte[6]; // 头部 + 2 字节身体
byte[] part2 = new byte[5]; // 5 字节身体
byte[] part3 = new byte[7]; // 7 字节身体
System.arraycopy(fullPacket, 0, part1, 0, 6);
System.arraycopy(fullPacket, 6, part2, 0, 5);
System.arraycopy(fullPacket, 11, part3, 0, 7);

DynamicLengthPacketHandler handler = new DynamicLengthPacketHandler();

List<byte[]> results = handler.handleData(part1);

System.out.println("第 1 次解析结果数量: " + results.size());
for (byte[] result : results) {
    System.out.println("解析内容: " + new String(result));
}

results = handler.handleData(part2);

System.out.println("第 2 次解析结果数量: " + results.size());
for (byte[] result : results) {
    System.out.println("解析内容: " + new String(result));
}

results = handler.handleData(part3);

System.out.println("第 3 次解析结果数量: " + results.size());
for (byte[] result : results) {
    System.out.println("解析内容: " + new String(result));
}
# 输出结果

第 1 次解析结果数量: 0
第 2 次解析结果数量: 0
第 3 次解析结果数量: 1
解析内容: HelloWorldJava
  1. 空数据包
byte[] packet = DynamicLengthPacketHandler.buildPacket("");

DynamicLengthPacketHandler handler = new DynamicLengthPacketHandler();

List<byte[]> results = handler.handleData(packet);

System.out.println("解析结果数量: " + results.size());
for (byte[] result : results) {
    System.out.println("解析内容: " + new String(result));
}
# 输出结果

解析结果数量: 1
解析内容: 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值