当前位置: 首页 > 知识库问答 >
问题:

协议缓冲区ParseFromString不检查消息结尾

公羊光明
2023-03-14

我发现了一个有趣的协议缓冲区问题。如果您有两条类似的消息,那么可以使用C API或命令行解析其中一条消息,就像解析另一条消息一样。

ParseFromString的有限文档没有提到它不需要使用所有字符串,如果不使用,它也不会失败。

我原以为ParseFromString无法解析类型为a的消息,如果它显示的是类型为B的消息。毕竟消息包含了额外的html" target="_blank">数据。然而,事实并非如此。示例脚本演示了该问题:

#!/bin/sh

cat - >./foobar.proto <<EOF
syntax = "proto3";
package demo;
message A
{
   uint64 foo = 1;
};

enum flagx { 
  y = 0; 
  z = 1; 
}

message B {
   uint64 foolish = 1;
   flagx bar = 2;
};

EOF

cat - >./mess.B.in.txtfmt <<EOF
foolish: 10
bar: y
EOF

cat - >./mess.in.txtfmt <<EOF
foo: 10
EOF

protoc --encode=demo.A foobar.proto <./mess.A.in.txtfmt >./mess.A.proto
protoc --encode=demo.B foobar.proto <./mess.B.in.txtfmt >./mess.B.proto
protoc --decode=demo.A foobar.proto >./mess.out.txtfmt <./mess.B.proto

echo "in: "
cat mess.B.in.txtfmt
echo "out: "
cat mess.out.txtfmt

echo "xxd mess.A.proto:"
xxd mess.A.proto

echo "xxd mess.B.proto:"
xxd mess.B.proto

输出为:

in: 
foolish: 10
bar: 20
out: 
foo: 10
xxd mess.A.proto:
00000000: 080a                                    
xxd mess.B.proto:
00000000: 080a

因此,对于消息A和消息B,二进制消息是相同的。

如果您更改协议以使您有另一个varint(uint64)而不是枚举,您将获得不同的二进制消息,但ParseFromString仍然会成功地将较长的消息解析为较短的消息。

为了真正混淆问题,它似乎还能够将较短的消息解析为较长的消息。

这是一个bug还是一个特性?

共有1个答案

公冶高义
2023-03-14

我认为这是出于设计,但文档可能会更好。

如果您试图使用API而没有首先阅读over-the-wire格式,则可能会出现这种混淆。wire格式并非如您所料与API无关。

wire格式强调紧凑性而非正确性。如果要检查消息的正确性,请使用其他方法。

您可以(可以说应该或必须)在邮件中包含以下一项或多项内容:

  • 消息类型字段
  • 消息长度字段
  • 一个校验和

关于能够将较短消息解析为较长消息的第二点,是因为在protocol buffers 3中,所有字段都是可选的。协议缓冲区2有一个必填字段的概念。它的删除引起了一些争议(例如,请参见为什么在协议缓冲区3中删除了required和optional

 类似资料:
  • 我有一个二进制数据缓冲区,我想存储在协议缓冲区中。 在留档(https://developers.google.com/protocol-buffers/docs/proto#scalar)中,它说类型等价于C中的。我无法相信这一点,所以我不得不尝试它,是的,这似乎是这样... 本协议: 给出一个包含以下内容的消息定义: 公共setter/getter API如下所示: 当然,这不是在消息中存储二

  • 而不是使用关系。关系GetRequest作为请求和响应。有什么方法可以将请求/响应转换为POJO? 我见过这个解决方案,但它比我想要的要复杂一些:将协议缓冲区转换为POJO 我正在使用翻新和谷歌协议缓冲区。 我所拥有的: 我想用的是: 关系: 我的请求最终是这样的,请求必须在这里构建...

  • 问题内容: 是否可以在Java中的协议缓冲区? C ++版本具有它:在这里 问题答案: 这是ParseFromString的实现(请注意,只需调用一个新对象): 您可以看到只是清除了消息,然后调用。尽管协议缓冲区的Java实现没有方法,但是您可以轻松实现它:

  • 试图使用Ionic 4中的协议缓冲区进行编码 我已经下载了协议并用它来生成一堆_pb.js文件,每个. proto文件一个。很好。 首先关注原型示例。这是示例代码: 我做了一些更改以匹配我的文件。更改proto文件的名称。但是我的proto文件中没有包名称。所以我只是使用了消息名称。首先这是我的. proto文件的开头: 下面是我修改后的代码: 这似乎不起作用。我的控制台显示: 我相信我已经成功地

  • 问题内容: 我正在使用gSoap将旧式C 系统重构为SOA。我们遇到了一些性能问题(非常大的XML),因此我的领导要我看一下协议缓冲区。我做到了,它看起来非常酷(我们需要C 和Java支持)。但是协议缓冲区是仅用于序列化的解决方案,现在我需要将其发送到Java前端。从C ++和Java角度来看,我应该使用什么来通过HTTP(只是内部网络)发送那些序列化的内容? PS。另一个人试图加速我们的gSoa

  • 两者都是序列化库,由谷歌开发人员开发。他们之间有什么大的区别吗?将使用协议缓冲区的代码转换为使用FlatBuffers需要大量工作吗?