2012-08-16 23 views
26

在我的服务器上,我们收到自描述消息(如定义here ......这不是那么容易,因为在C++中没有任何'好'的例子)。如何从一组已定义的描述符动态构建新的protobuf?

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

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

问题是,我如何获取每个已定义的描述符或消息并动态地生成一个包含所有已定义消息的“主”消息作为嵌套消息。这主要用于保存消息的当前状态。目前我们只是通过实例化服务器中每种消息的类型来处理这个问题(以保持跨不同程序的中心状态)。但是,当我们想要“保存”当前状态时,我们不得不按照定义的here将它们流式传输到磁盘。它们每次只能传输一条消息(大小前缀)。我们希望有一条消息(一条来统治它们),而不是稳定的单独消息流。这可以用于其他事情一旦制定出来(基于网络的优化和简单的序列化共享状态)

由于我们已经有了交叉链接和定义的描述符,人们会认为会有一种简单的方法来构建来自那些已经定义的消息的'新'消息。到目前为止,解决方案已经提到了我们。我们尝试创建自己的DescriptorProto,并从已定义的描述符中添加新类型的字段,但却迷失了方向(尚未深入探讨)。我们也研究过可能将它们添加为扩展名(目前未知如何实现)。我们是否需要创建我们自己的DescriptorDatabase(此时还不知道该怎么做)?

任何见解?


链接example source在BitBucket上。


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

我试图从一组已定义的消息中动态构建消息。这组已经定义的消息是通过使用官方C++ protobuf教程中(简要地)解释的“自描述”方法创建的(即,这些消息在编译后不可用)。这个新定义的消息将需要在运行时创建。

已尝试使用每个消息的直接描述符并尝试构建FileDescriptorProto。曾尝试查看DatabaseDescriptor方法。两者都没有运气。目前试图将这些定义的消息添加为另一个消息的扩展(甚至在编译时,这些定义的消息及其'描述符集'未被分类为扩展任何东西),这是示例代码开始的地方。

+0

哇......甚至没有评论...以下是我在哪里为止。这是我唯一拥有公共资源的人......它现在显然不能编译(直到最初创建ExtensionSet的那一端)......现在尝试将扩展路由作为另一个路由到目前为止,还有两个失败了。 http://goo.gl/VJhnk – g19fanatic 2012-08-22 03:26:26

+0

我现在遇到的问题是扩展标识符的初始化。我需要一个类来指定MessageTypeTraits到一个描述消息类型的类(可能要做我自己的模板魔法?),但到目前为止还没有成功...... – g19fanatic 2012-08-22 03:29:21

+1

老实说,我读了你的问题3次,并且仍然不明白你在描述什么。我认为这发生在大多数读者身上,这就是为什么你没有得到答复。你确实需要简化一些东西。此外,它真的感觉你正在构建一些复杂的东西,在那里可以更容易的解决方案。 – Codeguard 2012-08-22 12:38:07

回答

4

我能够动态地创建一个.proto文件来解决这个问题,加载一个Importer

唯一的要求是每个客户端发送它的原始文件(只在init中需要...而不是在完全执行期间)。服务器然后将每个proto文件保存到一个临时目录。如果可能,另一种方法是将服务器指向一个中心位置,该中心位置包含所有需要的proto文件。

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

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

如果任何人有任何关于如何使这个过程更好或如何做不同的建议,请说出来。

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

+4

你有没有一个你如何实现它的例子? – Dave 2013-11-19 12:58:34

1

什么所有的消息序列化为字符串,使主消息(字节)串序列,一拉

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

@ g19fanatic :如果这不符合你的要求,你能澄清你想达到的目标吗? – Managu 2012-08-22 14:19:03

+0

这正是我们目前正在做这件事的方式,但问题在于迅速将该组消息解析出来。由于消息之间没有固有的分隔符,因此我们将每条消息的大小存储在uint32前缀中。我们使用这个前缀来分别解析每条消息。我们试图做的是只有一条消息,然后我们序列化。当它解析出来的时候,它只需要调用一次而不是重复的getnextsize,解析下一条消息,重复一次。 – g19fanatic 2012-08-22 14:28:29

+2

好吧,把编码部分交给协议缓冲区,'serialized_sub_message'被'重复'。所以它仍然是一个循环('dispatch_serialized_message(message_set.serialized_sub_message(i))'),但是你不必处理编码的细节。 – Managu 2012-08-22 14:46:42

5

你需要一个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; 
}