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

How do I pack an INT32 into my MessagePack using Java?

我遇到了一个问题,我需要将 INT32 发送到另一个应用程序,但是根据我的阅读,messagepack.putIntmessagepack.putLong 将尝试将其优化为 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>

其他人遇到了同样的问题,并表示解决方案如下

"OK,所以我们发现了问题,似乎 metricTank 需要将消息对象的时间 属性 序列化为 INT32,但是 packInt(或 packLong)将始终尝试将其优化为 metricTank 不喜欢的 UINT32。因此我们不得不使用 addPayload 并序列化 MessagePacker.Code.INT32,然后是时间的实际 4 个字节 属性."

但我不确定该怎么做,而且我无法联系到 OP。

我尝试了以下方法,但它不起作用

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

bytes数组长度需为5,第一个字节为header,为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 而不是 UINT32 打包到我的 MessagePack 中,或者告诉我如何以正确的方式打包数据以便在接收应用程序上正确解包?


接收应用程序写在Go and uses the 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
    }
}

这会检查第一个字节,如果第一个字节等于 mint320xd2,那么接下来的四个字节是read,这是 long using getmint32

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

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

我忘记了 long 是 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)