在我当前的项目中,我需要通过网络发送一个包含一些 n 位字段的解析结构。例如:
- 协议版本:1字节
- 消息 ID:1 个字节
- 创建时间:6 个字节
- traceId:3 位
- 可靠性:7位
- ETC...
因此,我创建了一个简单的 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 Less Signigicant Bits 中有一个包含所需值的 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 字节的字节数组。显然,反解析是非常相似的过程。必须有一种正确的方法来做到这一点,但是,它确实有效......希望这对某人有所帮助!