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

标签 java networking bit-manipulation

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

  • 协议(protocol)版本:1字节
  • messageId:1字节
  • 创建时间:6字节
  • traceId:3 位
  • 可靠性:7 位
  • 等等...

因此,我创建了一个简单的 POJO 类来表示解析和解解析,但我对这些字段使用什么类型有一些疑问,因为这个决定可以使解析和解解析变得容易或有点噩梦。我必须说,通过网络发送的消息有一个非常具体的大小限制:它不能超过所有字段的总和。

我首先尝试使用字节来处理所有内容,然后使用 Message.getBytes() 方法来转换消息,对于那些小于字节的字段,使用按位运算来丢弃不必要的位。

我的方向是正确的还是有另一种更简单的方法来做到这一点?我只是觉得我在这里重新发明轮子,这感觉有点样板代码......

谢谢!

编辑:如果其他人在这里遇到困难,我会发布我如何解决这个问题(感谢工作中的同事帮助我解决这些问题),所以请继续阅读:

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

也就是说,假设我有两个字段,即 field1 和 field2,第一个字段为 7 位,另一个字段为 1 位。为了将这些结合起来,我只需执行以下技巧:

byte resultingByte = short2Byte((short) ((field1 % 128) * 2 + (field2 ? 1 : 0)));

请注意,field1 和 field2 都是短类型。我发现这是在位级别工作的最方便的方法。因此,我对第一个字段进行修改,确保只获得 7 位,将这些位向左移动 2,因为只需要移动一位。最后,我添加了字段 2 Short,它可以是 1 或 0。然后我在 8 个低有效位中添加了包含所需值的 Short。

我创建了从 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);
    }
}

最后我发送了一个 49 字节的字节数组。显然,解析是非常相似的过程。必须有一个正确的方法来做到这一点,但是,它有效......希望这对某人有帮助!

最佳答案

您可以使用ByteBufferBitSet类来写入和读取消息,但它仍然可能成为一场噩梦,甚至比纯位操作更糟糕(并且会影响性​​能)

关于java - 如何在 Java 中表示位字段(并发送它们),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17545601/

相关文章:

java - 如何测试回滚是否按预期工作?

ios - 排序 IP 地址

c - 读取 TCP 选项字段

c# - 用 2 的补码表示十六进制值

python - 给定任意长度的整数,Python 中按位非的确切定义是什么?

java - 从@WebService获取对spring bean的引用

java - 如何为名称中包含 "requires"(连字符)的 Artifact 添加 "-"

java - 非解释语言可以有垃圾收集器吗?

c++ - 在 C++ 中接收地址为 255.255.255.255 的广播数据包

c++ - 计算存储数字所需位数的最快方法是什么