如何使用Java将INT32打包到我的MessagePack中?

时间:2017-11-05 12:25:23

标签: java msgpack

我遇到了需要将INT32发送到其他应用程序的问题,但是从我读过的内容来看, messagepack.putInt messagepack.putLong < / em>将尝试将此优化为UINT32,这会导致接收应用程序出现问题。

接收应用程序正在向我提供错误消息

decode error, skipping message. msgp: attempted to decode type "uint" with method for "int"

我正在使用具有依赖性的maven

  <dependency>
   <groupId>org.msgpack</groupId>
   <artifactId>msgpack-core</artifactId>
   <version>0.8.13</version>
</dependency>

其他人有同样的问题,并说明解决方案如下

&#34; 好的,所以我们发现了问题,似乎metricTank要求将消息对象的time属性序列化为INT32,但是packInt(或packLong)总是会尝试将其优化为Uint32是metricTank不喜欢的。所以我们不得不使用addPayload和序列化MessagePacker.Code.INT32,然后使用time属性的实际4个字节。&#34;

但我不确定该怎么办,我无法联系OP。

我尝试过以下但是不起作用

ByteBuffer buf = ByteBuffer.allocate(1 + Long.BYTES);
buf.put(MessagePack.Code.INT32);
buf.putLong(md.time);
packer.addPayload(buf.array());

字节数组的长度必须为5,第一个字节是标头, 0xd2 ,其他4个字节需要为值

 ByteArrayOutputStream baos = new ByteArrayOutputStream();
            DataOutputStream dos = new DataOutputStream(baos);
            dos.writeLong(md.time);
            dos.close();
            byte[] longBytes = baos.toByteArray();

            ByteBuffer lBytes = ByteBuffer.allocate(4);
            for (int i = 0; i < 4; i++) {
                    lBytes.put(longBytes[i]);
            }

            ByteBuffer buf = ByteBuffer.allocate(5);
            buf.put((byte) 0xd2);
            buf.put(lBytes.array());

这不会产生错误,但收到时时间值不正确。

有人可以告诉我如何将INT32打包到我的MessagePack而不是UINT32,或者告诉我如何以正确的方式打包数据,以便在接收应用程序中正确解压缩?

接收应用程序是用Go编写的,并使用tinylib msgp库来解码数据

// ReadInt64Bytes tries to read an int64
// from 'b' and return the value and the remaining bytes.
// Possible errors:
// - ErrShortBytes (too few bytes)
// - TypeError (not a int)
func ReadInt64Bytes(b []byte) (i int64, o []byte, err error) {
    l := len(b)
    if l < 1 {
        return 0, nil, ErrShortBytes
    }

    lead := b[0]
    if isfixint(lead) {
        i = int64(rfixint(lead))
        o = b[1:]
        return
    }
    if isnfixint(lead) {
        i = int64(rnfixint(lead))
        o = b[1:]
        return
    }

    switch lead {
    case mint8:
        if l < 2 {
            err = ErrShortBytes
            return
        }
        i = int64(getMint8(b))
        o = b[2:]
        return

    case mint16:
        if l < 3 {
            err = ErrShortBytes
            return
        }
        i = int64(getMint16(b))
        o = b[3:]
        return

    case mint32:
        if l < 5 {
            err = ErrShortBytes
            return
        }
        i = int64(getMint32(b))
        o = b[5:]
        return

    case mint64:
        if l < 9 {
            err = ErrShortBytes
            return
        }
        i = getMint64(b)
        o = b[9:]
        return

    default:
        err = badPrefix(IntType, lead)
        return
    }
}

这将检查第一个字节,如果第一个字节等于 mint32 ,即 0xd2 ,则读取接下来的四个字节,这是长期使用 getmint32

func getMint32(b []byte) int32 {
    return (int32(b[1]) << 24) | (int32(b[2]) << 16) | (int32(b[3]) << 8) | (int32(b[4]))
}

1 个答案:

答案 0 :(得分:0)

在此特定问题中,接收应用程序必须接收INT32,并且bytes数组的长度必须为5。第一个字节是标题 0xd2 ,如OP中所示。这告诉解码方法它是INT32。接下来的四个4字节是时间值。

我忘了长8个字节,所以我们只需要使用一个整数的纪元时间。

        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        DataOutputStream dos = new DataOutputStream(baos);
        dos.writeInt((int)(md.time/1000));
        dos.close();
        byte[] timeBytes = baos.toByteArray();


        ByteBuffer buf = ByteBuffer.allocate(5);
        buf.put((byte) 0xd2);//header
        buf.put(timeBytes);//time value (int32 bytes not uint32)