如何在Java中表示位字段(并发送它们)

如何在Java中表示位字段(并发送它们),java,networking,bit-manipulation,Java,Networking,Bit Manipulation,在我当前的项目中,我需要通过网络发送一个包含一些n位字段的解析结构。例如: 协议版本:1字节 messageId:1字节 creationTime:6字节 traceId:3位 可靠性:7位 等等 因此,我创建了一个简单的POJO类来表示解析和解析,但我对这些字段使用什么类型有一些疑问,因为这个决定可能会使解析和解析变得容易,或者有点像噩梦。我必须说,通过网络发送的消息有一个非常具体的大小限制:它不能超过所有字段的总和 我首先考虑对所有内容使用字节,然后使用Message.getBytes(

在我当前的项目中,我需要通过网络发送一个包含一些n位字段的解析结构。例如:

  • 协议版本:1字节
  • messageId:1字节
  • creationTime:6字节
  • traceId:3位
  • 可靠性:7位
  • 等等
因此,我创建了一个简单的POJO类来表示解析和解析,但我对这些字段使用什么类型有一些疑问,因为这个决定可能会使解析和解析变得容易,或者有点像噩梦。我必须说,通过网络发送的消息有一个非常具体的大小限制:它不能超过所有字段的总和

我首先考虑对所有内容使用字节,然后使用Message.getBytes()方法转换消息,对于小于一个字节的字段,使用逐位操作丢弃不必要的位

我是朝着正确的方向走,还是有另一种更简单的方法?我只是觉得我在这里发明轮子,这感觉有点像样板代码

谢谢

编辑:如果有人在这里绊倒了,我会发布我是如何解决这个问题的(感谢一位同事帮助我解决了这些问题),所以请继续阅读:

幸运的是,我的协议套接字大小四舍五入到一个固定的字节数(49),那些小于字节大小的字段在最后加一个字节,这样我就可以在解析/解析之前将两个字段合并到一个字节中

也就是说,假设我有两个字段,比如field1和field2,第一个是7位,另一个只是一位。要将这些结合起来,我只需做以下操作:

byte resultingByte = short2Byte((short) ((field1 % 128) * 2 + (field2 ? 1 : 0)));
请注意,field1和field2都是短类型。我发现这是在位级别工作最方便的方法。因此,我修改了第一个字段,确保只得到7位,将位向左移动2,因为只需要移动一位。最后,我添加了字段2 short,它可以是1或0。然后,我有一个短的8个不太重要的位所需的值

我创建了商品方法以从short2Byte、Long和其他一些方法转换:

private byte [] to2Bytes(int in) {
    ByteBuffer ret = ByteBuffer.allocate(2);
    int val = in % 65536;

    short s1 = (short) (val / 256);
    short s0 = (short) (val % 256);

    ret.put(short2Byte(s1));
    ret.put(short2Byte(s0));

    return ret.array();
}

private byte [] to4Bytes(long in) {
    ByteBuffer ret = ByteBuffer.allocate(4);
    long div = 4294967296L;
    long val = in % div;
    int rem = 0;

    short s3 = (short) (val / 16777216L);
    rem = (int) (val % 16777216L);
    short s2 = (short) (rem / 65536);
    rem = rem % 65536;
    short s1 = (short) (rem / 256);
    short s0 = (short) (rem % 256);

    ret.put(short2Byte(s3));
    ret.put(short2Byte(s2));
    ret.put(short2Byte(s1));
    ret.put(short2Byte(s0));

    return ret.array();
}

private byte [] time2Bytes(Long time) {
    ByteBuffer ret = ByteBuffer.allocate(6);
    String hex = Long.toHexString(time).toUpperCase();
    while (hex.length() < 12) {
        hex = "0" + hex;
    }

    while (hex.length() > 12) {
        hex = hex.substring(1);
    }

    try {
        for (int i = 0; i < 6; i++) {
            String strByte = "" + hex.charAt(i*2) + hex.charAt(i*2 + 1);
            short b = Short.parseShort(strByte, 16);
            if (b > 127) {
                b -= 256;
            }
            ret.put((byte) b);
        }
    }
    catch (NumberFormatException e) {
        // Exception captured for correctness
        e.printStackTrace();
    }


    return ret.array();
}

private long bytes2time(byte b5, byte b4, byte b3, byte b2, byte b1, byte b0) {
    long l5, l4, l3, l2, l1, l0;
    l5 = byte2short(b5) * 1099511627776L;
    l4 = byte2short(b4) * 4294967296L;
    l3 = byte2short(b3) * 16777216L;
    l2 = byte2short(b2) * 65536L;
    l1 = byte2short(b1) * 256L;
    l0 = byte2short(b0) * 1L;
    return  l5 + l4 + l3 + l2 + l1 + l0;
}

private long bytes2long(byte b3, byte b2, byte b1, byte b0) {
    long l3, l2, l1, l0;
    l3 = byte2short(b3) * 16777216L;
    l2 = byte2short(b2) * 65536L;
    l1 = byte2short(b1) * 256L;
    l0 = byte2short(b0) * 1L;
    return  l3 + l2 + l1 + l0;
}

private int bytes2int(byte b1, byte b0) {
    return (int)byte2short(b1) * 256 + (int)byte2short(b0);
}

private short byte2short(byte b) {
    if (b < 0) {
        return (short) (b+256);
    }
    return (short)b;
}

private byte short2Byte(short s) {
    if (s < 128) {
        return (byte) s;
    }
    else {
        return (byte) (s-256);
    }
}
private byte[]到2字节(int-in){
ByteBuffer ret=ByteBuffer.allocate(2);
int val=in%65536;
短s1=(短)(val/256);
短s0=(短)(val%256);
ret.put(short2Byte(s1));
回输量(短2字节(s0));
返回ret.array();
}
专用字节[]到4字节(长入){
ByteBuffer ret=ByteBuffer.allocate(4);
长div=4294967296L;
长val=单位为%div;
int-rem=0;
短s3=(短)(val/16777216L);
rem=(int)(val%16777216L);
短s2=(短)(rem/65536);
雷姆=雷姆%65536;
短s1=(短)(rem/256);
短s0=(短)(rem%256);
ret.put(short2Byte(s3));
ret.put(short2Byte(s2));
ret.put(short2Byte(s1));
回输量(短2字节(s0));
返回ret.array();
}
专用字节[]时间2字节(长时间){
ByteBuffer ret=ByteBuffer.allocate(6);
字符串hex=Long.toHexString(time).toUpperCase();
while(十六进制长度()<12){
hex=“0”+十六进制;
}
while(十六进制长度()>12){
十六进制=十六进制子串(1);
}
试一试{
对于(int i=0;i<6;i++){
字符串strByte=“”+十六进制字符(i*2)+十六进制字符(i*2+1);
short b=short.parseShort(标准红细胞,16);
如果(b>127){
b-=256;
}
ret.put((字节)b);
}
}
捕获(数字格式){
//为正确性捕获异常
e、 printStackTrace();
}
返回ret.array();
}
专用长字节2时间(字节b5、字节b4、字节b3、字节b2、字节b1、字节b0){
长l5,l4,l3,l2,l1,l0;
l5=字节2短(b5)*109951162776L;
l4=字节2短(b4)*4294967296L;
l3=字节2短(b3)*16777216L;
l2=字节2短(b2)*65536L;
l1=字节2短(b1)*256L;
l0=字节2短(b0)*1L;
返回l5+l4+l3+l2+l1+l0;
}
专用长字节2long(字节b3、字节b2、字节b1、字节b0){
长l3,l2,l1,l0;
l3=字节2短(b3)*16777216L;
l2=字节2短(b2)*65536L;
l1=字节2短(b1)*256L;
l0=字节2短(b0)*1L;
返回l3+l2+l1+l0;
}
专用整型字节2int(字节b1,字节b0){
返回(int)字节短(b1)*256+(int)字节短(b0);
}
专用短字节2短(字节b){
if(b<0){
返回(短)(b+256);
}
返回(短)b;
}
专用字节短2字节(短s){
如果(s<128){
返回(字节)s;
}
否则{
返回(字节)(s-256);
}
}

最后,我将发送一个包含49个字节的字节数组。显然,分离过程非常相似。必须有一个适当的方法来做到这一点,但好吧,它的工作…希望这有助于别人

您可以使用和类来写和读消息,但它仍然可能成为一场噩梦,甚至比纯位操作更糟(这将影响性能)

这将是一个问题:“我必须说,通过网络发送的消息有一个非常具体的大小限制:它不能超过所有字段的总和”你在说什么网络协议?我在用UDP包封装消息。我不介意将消息本身打包到几个UDP包中,但是最大消息负载大小是固定的。是的,我在考虑使用位集。我怀疑的是那些字段,比如说6位,我存储在一个字节中。我可以屏蔽我想要的值,但我不确定如何在位的基础上进行迭代,并在位集中添加每个位……我认为您可以为此实现迭代器模式。此外,您还可以实现像“addBits(long source,int count)”这样的方法,以获取“count”低有效位并将其添加到您的位集中。在您的示例中,为什么第一个参数是long?我想知道…我的消息中的大多数元素都是数字的,因此,我可以使用byte、short和int来表示它们,但是对于那些<1字节的元素,我使用byte。有了ByteBuffer,我可以加上一个b