Java 具有位大小定义的自定义序列化和反序列化

Java Custom Serialization and Deserialization with Bit size definitions

问题: 我需要从具有固定数据包格式定义的电子设备实现网络输入 reader。它有页眉、页脚和数据主体。数据包中的字段以位为单位定义。

示例: 字段 sequence_number 变量是编号为 8 到 31 的位,ack_status 是位 32。如何创建自定义序列化函数以便我可以将 java 对象与字节相互转换[] 从数据包中读取?

在 32 位数据包中

StartOfPacketHeader 4 位

CommandCode 4位

序列号23位

AckStatus 1bit

如何使用 byte[] 构造函数和 toBytes() 方法为此对象制作 Java 包装器 class。

使用可序列化接口无法控制单个数据大小。数据大小可能是奇数值,如 3 位或 18 位变量。我无法根据位指定变量的长度。

到目前为止我做了什么:

源实际上发送无符号整数,这意味着Java int 类型无法处理其整个范围。我需要定义所有数据类型来处理所有情况。我已经使用 BitSet class 执行 byte[] 到 Long 的转换,但它太乏味和令人困惑,因为 bitset 默认将位顺序反转为 Little Endian。

总结:

如何以最有效的方式将我从网络读取的 bytes[] 转换为我的对象,反之亦然,并为每个字段自定义定义?

您为此使用 DataInputStreamDataOutputStream,为了提高效率,在它们下面分别使用 BufferedInputStreamBufferedOutputStream。您必须自己编写位字段,但是这些 类 提供了网络字节顺序中的所有 Java 原语。

对于您发布的数据包,您需要这样的东西:

class Packet
{
    private byte    header;
    private byte    commandCode;
    private int     sequenceNumber;
    private boolean ackStatus;

    void    write(DataOutput out) throws IOException
    {
        int wirePacket = header|(commandCode << 4)|(sequenceNumber << 8);
        if (ackStatus)
        {
            wirePacket |= 0x80000000;
        }
        out.writeInt(wirePacket);
    }

    static Packet   read(DataInput in) throws IOException
    {
        Packet  packet = new Packet();
        int wirePacket = in.readInt();
        packet.header = (byte)(wirePacket & 0x0f);
        packet.commandCode = (byte)((wirePacket >>> 4) & 0x0f);
        packet.sequenceNumber = (wirePacket >>> 8) & 0x7FFFFF;
        packet.ackStatus = (wirePacket & 0x80000000) != 0;
        return packet;
    }
    // getters and setters. The setters must ensure that the values don't go out of range.
}