【问题标题】:Protobuf Doubles Serializing as Null BytesProtobuf 将序列化加倍为空字节
【发布时间】:2015-09-25 10:04:10
【问题描述】:

我使用 Google Protobuf 2.6.1 创建了一个非常简单的 java 类,结构如下:

required int64 tid = 1;
required int64 tid = 1;
required string clOrdID = 2;
required string execID = 3;
required string ticketType = 4;
optional string lastMkt = 5;
required double lastQty = 6;
required double cumQty = 7;
required double lastPx = 8;
required double avgPx = 9;
optional string lastCapacity = 10;
required int64 transactionTime = 11;
required int64 reportTime = 12;

在构建类并使用测试数据填充这些字段后,我将使用 .toByteArray() 方法将其转换为字节数组:

double d = 99.0;
FillProto fillProto = FillProto.newBuilder()
                        .setTid(n)
                        .setClOrdID("ClOrdID")
                        .setExecID("ExecID")
                        .setTicketType("ticketType")
                        .setLastMkt("LastMkt")
                        .setLastQty(d)
                        .setCumQty(d)
                        .setLastPx(d)
                        .setAvgPx(d)
                        .setLastCapacity("LastCapacity")
                        .setTransactionTime(now.getTime())
                        .setReportTime(now.getTime())
                        .build();

Log.info(class_,method_,"Sending through:\n" + new String(fillProto.toByteArray()));

我通过 Solace 队列发送 ByteArray,在另一端消费后,我尝试使用 FillProto.parseFrom(byte[]) 构建另一个对象,但出现错误:“在解析协议消息时,输入意外地在田野中间结束。”。 ByteArray 看起来不错,直到标记为 double 的字段都输出为 null(00 字节)。有谁知道这里发生了什么?

下面的字节数组:

  08 05 12 07 63 6c 4f 72    64 49 44 1a 06 65 78 65    ....clOrdID..exe
  63 49 44 22 0a 74 69 63    6b 65 74 54 79 70 65 2a    cID".ticketType*
  07 6c 61 73 74 4d 6b 74    31 00 00 00 00 00 c0 58    .lastMkt1......X
  40 39 00 00 00 00 00 c0    58 40 41 00 00 00 00 00    @9......X@A.....
  c0 58 40 49 00 00 00 00    00 c0 58 40 52 0c 4c 61    .X@I......X@R.La
  73 74 43 61 70 61 63 69    74 79 58 b0 8b a8 ce e6    stCapacityX.....
  29 60 b0 8b a8 ce e6 29                               )`.....)

【问题讨论】:

  • new String(fillProto.toByteArray()) 可能会做出可怕的事情。不要像这样将随机原型转储到 String 中,使用某种编码。除此之外——99.0 在其 IEEE 754 二进制表示中确实有许多零位。会这样吗?
  • 同意路易斯。你有任何证据表明这种编码不正确吗?
  • 我将字节数组作为字节消息通过 Solace 队列。当我在另一端使用它并尝试使用 FillProto.parseFrom(byte[]) 创建另一个 FillProto 对象时,我收到一个错误,即输入在字段中间意外结束。从读取另一个线程看来,这可能是由字节数组中的空值引起的(使用 msg.dump 输出)。我正在通过这个队列的其他没有任何双打的原型对象正在另一边重建良好。
  • 没关系,原来我没有为那个特定的原型使用 .parseFrom(byte[])。我有一个 if 语句,根据检索到的数据类型将代码分成不同的路径,并且该特定块尚未从旧方法更新。完全是用户错误。

标签: java serialization double protocol-buffers


【解决方案1】:

这是正常的。使用标准的 8 字节 IEEE-754 表示来表示双精度。双精度值零表示为全零,大多数其他值也将包含零。

听起来您的消息传递基础架构旨在对以 NUL 结尾的文本字符串进行操作。此类基础设施不适用于原始 Protobuf 内容,因为它会在第一个 NUL 字节处截断消息。通常,您不能在为文本设计的上下文中使用原始 Protobuf 数据,因为可能会发生各种损坏。请特别注意,永远不要将 protobuf 字节传递给 new String(),因为 String 存储的是 Unicode 文本,而不是字节。

如果您需要在需要文本的地方传输 Protobuf,则需要对数据进行 base64 编码以防止此类损坏 - base64 允许将原始字节放置在文本上下文中,但会增加数据的整体大小33%。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2022-01-22
    • 2021-10-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多