您所描述的内容实际上已经由C
++和Java中的协议缓冲区实现支持。您所需要做的就是传输一个
FileDescriptorSet,
google/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()构建的依赖项。
从那里,你可以使用
FileDescriptor的
findMessageTypeByName()找到
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而服务器将其视为子消息,从而避免了客户端知道该定义该子消息。``



