当前位置: 首页 > 面试题库 >

运行时生成的协议缓冲区对象

闻人树
2023-03-14
问题内容

我的一位同事提出了在运行时生成协议缓冲区类的想法。含义:

  • 有C ++服务器应用程序和Java客户端应用程序通过TCP / IP通过协议缓冲区消息进行通信。
  • C ++应用程序在不同版本中可能具有不同的架构,并且不一定向后兼容
  • 有与此服务器通信的Java应用程序,该应用程序应支持所有可能的服务器版本。

这个想法是服务器将协议缓冲区的定义作为初始握手的一部分发送,并且Java应用程序在运行时生成该类并将其用于与服务器进行通信。

我不知道这是否是至关重要的想法,以及这种用例是否有实用程序。

谢谢


问题答案:

您所描述的内容实际上已经由C
++和Java中的协议缓冲区实现支持。您所需要做的就是传输一个FileDescriptorSetgoogle/protobuf/descriptor.proto其中包含定义了FileDescriptorProto代表每个相关.proto文件的,然后用于DynamicMessage在接收端解释消息。

FileDescriptorProto在C ++中获取Foo该文件中定义的给定消息类型,请执行以下操作:

google::protobuf::FileDescriptorProto file;
Foo::descriptor().file()->CopyTo(&file);

FileDescriptorProto定义所需类型的所有s以及它们导入的所有文件放入FileDescriptorSet原型。请注意,您可以使用google::protobuf::FileDescriptor(由返回的东西Foo::descriptor().file())遍历依赖关系,而不必显式命名每个依赖关系。

现在,发送FileDescriptorSet给客户端。

在客户端上,用于FileDescriptor.buildFrom()将每个转换FileDescriptorProto为live
Descriptors.FileDescriptor。您必须确保先构建依赖项,然后再构建依赖项,因为在构建依赖项时必须提供已经buildFrom()构建的依赖项。

从那里,你可以使用FileDescriptorfindMessageTypeByName()找到Descriptor您所关心的具体消息类型。

最后,您可以调用DynamicMessage.newBuilder(descriptor)以为所讨论的类型构造一个新的构建器实例。
DynamicMessage.Builder实现该Message.Builder接口,该接口具有字段,getField()并且setField()可以动态地(通过指定相应的FieldDescriptors)操纵消息的字段。

同样,您可以调用DynamicMessage.parseFrom(descriptor,input)解析从服务器收到的消息。

注意,它的一个缺点DynamicMessage是它相对较慢。从本质上讲,它就像一种解释语言。生成的代码更快,因为编译器可以针对特定类型进行优化,而编译器DynamicMessage必须能够处理任何类型。

但是,实际上没有解决方法。即使您运行了代码生成器并在运行时编译了该类,实际 使用
新类的代码仍将是您在知道要使用的类型之前编写的代码。因此,它仍然必须使用反射或类似反射的接口来访问消息,这比为特定类型手写代码要慢。

好吧,这取决于。客户端实际上将从服务器收到的此架构 什么?通过网络传输模式并不能使客户端与该协议版本兼容,客户端仍必须 了解
协议的含义。如果协议已在向后兼容的方式被改变,这几乎肯定意味着该 意思
协议的名称已更改,并且客户端代码必须更新(是否传输模式)。唯一可以期望客户端无需更新就可以继续工作的情况是,客户端仅执行仅取决于消息内容而不取决于消息含义的通用操作时,例如,客户端可以将消息转换为JSON不必知道这意味着什么。但这是相对不寻常的,尤其是在应用程序的客户端。这正是Protobufs默认不发送任何类型信息的原因-
因为它通常是无用的,因为如果接收者不知道 含义 ,则该架构是无关紧要的。

如果问题在于服务器正在向客户端发送消息,这些消息根本不打算被解释,而只是在稍后发送回服务器,则客户端根本不需要架构。只是将消息发送为bytes,不必理会它。请注意,bytes包含类型为编码的消息的字段在线路上Foo看起来与类型实际声明为的字段完全相同Foo。实际上,您可以针对.proto文件的稍有不同的版本来编译客户端和服务器,在该版本中,客户端看到的是特定字段,bytes而服务器将其视为子html" target="_blank">消息,从而避免了客户端知道该定义该子消息。``



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

  • 问题内容: 我想做一个小的更改,深入到Java协议缓冲区对象的树中。 我可以使用该方法来制作一个新对象,该对象是旧对象的克隆并进行一些更改。 当深入执行此操作时,代码将变得难看: (这只是4个级别,我通常会处理5-8个级别。) 有没有更好的办法? 问题答案: 另一个选择是(我认为;已经有一段时间了): 注意,这没有任何效率。您仍在复制foo,bar,baz和quux。

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

  • 当我尝试运行gtfs\u realtime\u pb2时,我遇到以下错误。py(通过google的协议缓冲区运行gtfs-realtime.proto生成的python代码): 这是指向我遇到问题的特定代码的链接:https://github.com/mattwigway/gtfsrdb 以及安装谷歌协议缓冲区的链接: https://developers.google.com/protocol-

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

  • 在阅读这个相当长的问题之前,我提出了一个bughttps://github.com/GoogleCloudPlatform/python-docs-samples/issues/1103. 原型包和名称解析的留档状态 您可以使用其他定义。通过导入原始文件。导入另一个。在proto的定义中,您可以在文件的顶部添加一条import语句。 我的依赖于annotations.proto将HTTP/JSON