如何从一组已定义的描述符动态构建新的 protobuf

How to dynamically build a new protobuf from a set of already defined descriptors?

本文关键字:描述 动态 构建 protobuf 定义 一组      更新时间:2023-10-16

在我的服务器上,我们收到自我描述的消息(定义如此处...顺便说一句,这并不容易,因为在 C++ 中没有任何"好"的例子)。

在这一点上,我从这些自我描述的消息中创建消息没有问题。我可以获取FileDescriptorSet,遍历每个FileDescriptorProto,将每个添加到DescriptorPool中(使用BuildFile,它也给了我每个定义的FileDescriptor)。

从这里,我可以创建在FileDescriptorSet中定义的任何消息,使用DP实例化的DynamicMessageFactory并调用GetPrototype(这很容易做到,因为我们的SelfDescribedMessage需要消息full_name(),因此我们可以调用DP的FindMessageTypeByName方法,为我们提供正确编码的消息原型)。

问题是我如何获取每个已经定义的描述符或消息,并动态构建一个"主"消息,其中包含所有定义的消息作为嵌套消息。这将主要用于保存消息的当前状态。目前,我们只需在服务器中实例化每条消息的类型来处理这个问题(以在不同的程序中保持中心状态)。但是,当我们想要"保存"当前状态时,我们被迫将它们流式传输到此处定义的磁盘。它们一次流式传输一条消息(带有大小前缀)。我们希望有一条消息(一条来统治所有消息),而不是稳定的单独消息流。一旦解决,这可以用于其他事情(基于网络的共享状态,具有优化和轻松的序列化)

由于我们已经有了交叉链接和定义的描述符,人们会认为有一种简单的方法可以从那些已经定义的描述符中构建"新"消息。到目前为止,解决方案已经暗示了我们。我们尝试创建自己的描述符Proto,并从我们已经定义的描述符中添加该类型的新字段,但迷路了(尚未深入研究)。我们还考虑了可能将它们添加为扩展(目前不知道如何这样做)。我们是否需要创建自己的描述符数据库(目前也不知道如何做到这一点)?

有什么见解吗?


位桶上的链接示例源。


希望这个解释会有所帮助。

我正在尝试从一组已定义的消息动态构建消息。已经定义的消息集是通过使用官方 c++ protobuf 教程中解释的"自描述"方法(简要地)创建的(即这些消息不以编译形式提供)。需要在运行时创建此新定义的消息。

尝试对每条消息使用直接描述符,并尝试构建文件描述符Proto。尝试查看数据库描述符方法。两者都没有运气。 目前正在尝试将这些定义的消息作为扩展添加到另一条消息中(即使在编译时,这些定义的消息及其"描述符集"也没有被归类为扩展任何内容),这是示例代码开始的地方。

你需要一个protobuf::DynamicMessageFactory

{
  using namespace google;
  protobuf::DynamicMessageFactory dmf;
  protobuf::Message* actual_msg = dmf.GetPrototype(some_desc)->New();
  const protobuf::Reflection* refl = actual_msg->GetReflection();
  const protobuf::FieldDescriptor* fd = trip_desc->FindFieldByName("someField");
  refl->SetString(actual_msg, fd, "whee");
  ... 
  cout << actual_msg->DebugString() << endl;
}

我能够通过动态创建一个 .proto 文件并使用导入器加载它来解决这个问题。

唯一的要求是每个客户端要么发送其原型文件(仅在 init 时需要...不是在完全执行期间)。然后,服务器将每个原型文件保存到临时目录。如果可能的话,另一种方法是将服务器指向保存所有需要的原型文件的中央位置。

这是通过首先使用DiskSourceTree将实际路径位置映射到程序中的虚拟路径位置来完成的。然后构建 .proto 文件以导入通过 AND 发送的每个 proto 文件,并在"主消息"中定义一个可选字段。

master.proto保存到磁盘后,我使用导入器导入它。现在使用 Importers DescriptorPool 和 DynamicMessageFactory,我能够在一条消息下可靠地生成整个消息。我将在今晚晚些时候或明天举一个例子来说明我所描述的内容。

如果有人对如何使此过程更好或如何做得不同有任何建议,请说出来。

在赏金即将到期之前,我将不回答这个问题,以防其他人有更好的解决方案。

将所有消息序列化为字符串,并使主消息成为(字节)字符串序列怎么样,就像

message MessageSet
{
  required FileDescriptorSet proto_files = 1;
  repeated bytes serialized_sub_message = 2;
}