未检查/强制执行 Protobuf C++ 必填字段

Posted

技术标签:

【中文标题】未检查/强制执行 Protobuf C++ 必填字段【英文标题】:Protobuf C++ required fields are not checked/enforced 【发布时间】:2017-05-17 06:44:40 【问题描述】:

我是 Protocol Buffers 的新手,目前我看到以下问题:

我们将proto2 语法与Protocol Buffers 3.2.0 库一起使用,并观察到required 字段在序列化期间未强制执行。

这里有一个 Catch C++ 测试的基本示例:

syntax = "proto2";

package simple_test;

message SimpleMessage

  required string field1 = 1;
  required string field2 = 2;


#include "simple.pb.h"
#include <catch.hpp>
#include <string>

SCENARIO("Verify that serialization with missing required fields fails", "[protobuf]")

  GIVEN("a message")
  
    simple_test::SimpleMessage m;

    WHEN("field1 is set and field2 is not and both are required")
    
      m.set_field1("aaa");

      THEN("serializing this message to string buffer must fail")
      
        std::string buffer;
        CHECK_FALSE(m.SerializeToString(&buffer));
        REQUIRE(buffer.empty());
      
    
  

m.SerializeToString(&amp;buffer) 返回true 并且buffer.empty()false

我知道的

required 字段已在 Protobuf v3 中删除。

我的问题

我是否可以使用 Protobuf v3 强制执行这些检查的设置或任何类型的配置开关?

用例会发生什么:

proto2 使用 Protobuf v3 编译器编译的消息。此消息以部分填写的必填字段结束,并将发送到强制执行 required 字段的 Protobuf v2 端点。这是否实际上意味着只发送了字节,因为消息无效并且将被拒绝?

我应该从 v3.2.0 降级到 2.x 以禁止在客户端发送不完整的消息吗?

【问题讨论】:

【参考方案1】:

我带来了这份我之前监督过的文档:

Standard Message Methods 并且有以下文档:

标准消息方法

每个消息类还包含许多其他方法,可让您检查或操作整个消息,包括:

bool IsInitialized() const;:检查是否所有必填字段都已设置。

这就是我需要的! Protobuf 再次很棒!

【讨论】:

【参考方案2】:

我是否可以使用 Protobuf v3 强制执行这些检查的设置或任何类型的配置开关?

您是否尝试过在调试配置中构建 protobuf?我想你会发现它会在这种情况下断言。

用例会发生什么:

proto2 使用 Protobuf v3 编译器编译的消息。此消息以部分填写的必填字段结束,并将发送到强制执行必填字段的 Protobuf v2 enpoint。这是否实际上意味着只发送了字节,因为消息无效并且将被拒绝?

在这种情况下,接收者可以ParsePartialFromXXX 接收发送的内容。他可以用message.has_xxx()测试消息的有效性

我应该从 v3.2.0 降级到 2.x 以禁止在客户端发送不完整的消息吗?

我不会。也许为每种消息类型编写一个检查器来断言每个必填字段都存在。更好的是,以 proto3 方式考虑它,并将缺失的字段视为接收器中的默认值。 protobuf 文档建议永远不要将 required 字段添加到现有消息类型,并建议在创建字段 required 之前“仔细考虑”。您可以将其理解为“糟糕,必填字段的概念是错误的”。

【讨论】:

感谢您的回复,即使它对 Protobuf 变异的方式令我失望。调试模式不是一个选项,即使我发现它断言比什么?关于其他两个问题,我阅读了必填字段,在我们的案例中,我不想拥有任何灵活的协议。这应该是“我的方式或高速公路”。我还读到,即使在谷歌,也有两个阵营在支持required 并反对它。 @ovanes 我知道这对我们 c++ 人来说很失望——我们已经习惯了强类型。但是当然protobuf最终只是一个序列化协议。服务器/接收者必须是正确与否的最终仲裁者。恶意客户端可以发送任何内容。因此,在我们的 protobuf rpc 实现中,服务器会检查所有不变量,如果消息格式错误或不完整,则返回异常通知。 是的,但这也违反了 DRY。有多少人使用 Protobuf 并且所有人都必须实施这种required 检查。我了解是否有人需要检查更复杂的不变量,例如该字段的值 X 是否比另一个应该具有 Y。但是如果有 required 这样的东西它也应该工作:(而不是问:是的!只是膨胀您的代码包含大量 if 语句并进行检查。AFAIK Protobuf 甚至不支持访问者模式,在没有 ifs 的情况下进行这种调度和验证。 @ovanes 您可以遍历消息描述符的字段描述符并检查是否需要,因此您可以使用一个引用基类Message的函数检查所有消息@

以上是关于未检查/强制执行 Protobuf C++ 必填字段的主要内容,如果未能解决你的问题,请参考以下文章

未强制执行 C++ 虚函数

未强制执行唯一约束检查

PROTOBUF INT64 检查先前输入的数据 c++

如何停止使用 protobuf3 打印错误消息“无法解析类型的消息,因为它缺少必填字段”

填字游戏搜索的最佳数据结构

程序员的算法趣题Q66: 设计填字游戏