天道酬勤,学无止境

How to log Protobuf string in nested objects in a human-readable way?

Given a proto file:

syntax = "proto3";
package hello;

message TopGreeting {
    NestedGreeting greeting = 1;
}

message NestedGreeting {
    Greeting greeting = 1;
}

message Greeting {
    string message = 1;
}

and the code:

public class Main {
    public static void main(String[] args) {
        System.out.printf("From top: %s%n", newGreeting("오늘은 무슨 요일입니까?"));
        System.out.printf("Directly: %s%n", "오늘은 무슨 요일입니까?");
        System.out.printf("ByteString: %s", newGreeting("오늘은 무슨 요일입니까?").toByteString().toStringUtf8());
    }

    private static Hello.TopGreeting newGreeting(String message) {
        Hello.Greeting greeting = Hello.Greeting.newBuilder()
                .setMessage(message)
                .build();
        Hello.NestedGreeting nestedGreeting = Hello.NestedGreeting.newBuilder()
                .setGreeting(greeting)
                .build();
        return Hello.TopGreeting.newBuilder()
                .setGreeting(nestedGreeting)
                .build();
    }
}

Output

From top: greeting {
  greeting {
    message: "\354\230\244\353\212\230\354\235\200 \353\254\264\354\212\250 \354\232\224\354\235\274\354\236\205\353\213\210\352\271\214?"
  }
}

Directly: 오늘은 무슨 요일입니까?

ByteString: 
%
#
!오늘은 무슨 요일입니까?

How do I print the message in a human-readable way? As you can see, converting to ByteString prints the UTF-8 characters alright, but also prints some other garbage % and #.

评论

Answering my own question, I solved this issue by digging through Protobuf source code.

System.out.println(TextFormat.printer().escapingNonAscii(false).printToString(greeting))

Output:

greeting {
  greeting {
    message: "오늘은 무슨 요일입니까?"
  }
}

toString uses the same mechanism but with escapingNonAscii(true) (default when omitted).

Also see this answer for how to convert Octal sequences to UTF-8 characters in case you don't have access to the source code, only logs.

The protobuf binary format isn't human readable and you shouldn't attempt to make it so. There is a JSON variant if you need, but frankly it would be better to log the interpreted data, not the payloads.

受限制的 HTML

  • 允许的HTML标签:<a href hreflang> <em> <strong> <cite> <blockquote cite> <code> <ul type> <ol start type> <li> <dl> <dt> <dd> <h2 id> <h3 id> <h4 id> <h5 id> <h6 id>
  • 自动断行和分段。
  • 网页和电子邮件地址自动转换为链接。

相关推荐
  • 尝试减少 JSON 大小是否值得付出努力?(Is it worth the effort to try to reduce JSON size?)
    问题 我正在从移动应用程序提交相对大量的数据(最多 1000 个 JSON 对象),我通常会像这样编码: [{ id: 12, score: 34, interval: 5678, sub: 9012 }, { id: ... }, ...] 我可以通过提交数组数组来使有效负载更小: [[12, 34, 5678, 9012], [...], ...] 在属性名称上节省一些空间,并在服务器上重新创建对象(因为架构是固定的,或者至少它是服务器和客户端之间的契约)。 然后在POST请求中提交有效负载,最有可能通过 3G 连接(或可能是 wifi)。 看起来我通过使用嵌套数组节省了一些带宽,但我不确定在应用gzip时它是否明显,我不确定如何精确和客观地测量差异。 另一方面,嵌套数组感觉不是一个好主意:它们的可读性较差,因此在调试时更难发现错误。 此外,由于我们正在降低可读性,我们可以将数组展平,因为每个子数组都有固定数量的元素,服务器可以将其切片并再次重建对象。 非常感谢有关此主题的任何进一步阅读材料。 回答1 JSONH,又名 hpack,https://github.com/WebReflection/JSONH 与您的示例非常相似: [{ id: 12, score: 34, interval: 5678, sub: 9012 }, { id: 98, score: 76
  • JSON和协议缓冲区之间是否存在标准映射?(Is there a standard mapping between JSON and Protocol Buffers?)
    问题 从公告博客文章的评论中: 关于JSON:JSON的结构类似于协议缓冲区,但是协议缓冲区二进制格式仍然更小且编码更快。 但是,JSON为协议缓冲区提供了一种出色的文本编码-编写编码器/解码器是很简单的,该编码器/解码器使用protobuf反射将任意协议消息与JSON相互转换。 这是与AJAX应用程序通信的好方法,因为让用户在访问您的页面时下载完整的protobuf解码器可能太多了。 编写一个映射可能是微不足道的,但是在两者之间是否有一个单独的“显而易见的”映射,任何两个独立的开发团队都会自然地适应于此? 如果两个产品支持PB数据并且因为它们共享相同的.proto规范而可以互操作,我想知道如果它们独立引入相同规范的JSON反射,它们是否仍然可以互操作。 可能会做出一些任意决定,例如枚举值应该用字符串(对于人类来说是典型的JSON可读)还是整数值来表示? 那么,是否存在已建立的映射以及用于从.proto规范生成JSON编码器/解码器的任何开源实现? 回答1 是的,自协议缓冲区版本3.0.0(2016年7月28日发布)以来,存在发行说明中提到的“ JSON中定义明确的编码,可以替代二进制原型编码” https://github.com/google/protobuf/releases/tag/v3.0.0 回答2 可能对您有所帮助http://code.google.com/p
  • Protobuf-net : Nested IEnumerable objects
    I am using Protobuf-net to serialize a custom nested list. I understand that native lists cannot be nested directly, which is why I have used a container object for the inner list. However, I would also like to make my container objects IEnumerable but this means Protobuf-net throws it out with the error: Nested or jagged lists and arrays are not supported Here is an example of my list structure which causes the error: [ProtoContract] public class MyOuterList<T> { [ProtoMember(1)] readonly List<MyInnerList<T>> nestedData = new List<ObjectList<T>>(); } [ProtoContract] public class MyInnerList<T
  • 对象序列化 - 从 C# 或 java 到 Objective C(Object serialization - from C# or java to Objective C)
    问题 服务器端 - C# 或 java 客户端目标 C 我需要一种在 C#\java 中序列化对象并在 Objective C 中反序列化它的方法。我是 Objective C 的新手,我想知道在哪里可以获得有关此问题的信息。 谢谢。 回答1 除了明显的 JSON/XML 解决方案,protobuf 也可能很有趣。 它有 Java//c++/python 后端,第 3 方也为 C# 和 Objective-c 创建了后端(尽管从未使用过)。 主要优点是解析速度快得多[1],小得多[2],因为它是一种二进制格式,而且版本控制从一开始就是一个重要因素。 [1] 谷歌声称是 XML 的 20-100 倍 [2] 3-10次同来源 另一种类似于 protobufs 的技术是 Apache Thrift。 Apache Thrift 是一个用于可扩展的跨语言服务开发的软件框架。 Apache Thrift 允许您在一个简单的定义文件中定义数据类型和服务接口。 将该文件作为输入,编译器生成用于轻松构建跨编程语言无缝通信的 RPC 客户端和服务器的代码。 回答2 JSON 用于相对直接的对象图 XML/REST 用于更复杂的对象图(数组/集合/嵌套数组等之间的区别) 回答3 苏兹。 我正在使用它。 从 i-os 应用程序调用 Web 服务非常容易。 您不必编写代码来序列化对象。 回答4
  • Protobuf-net:嵌套的IEnumerable对象(Protobuf-net : Nested IEnumerable objects)
    问题 我正在使用Protobuf-net序列化自定义的嵌套列表。 我知道本机列表不能直接嵌套,这就是为什么我对内部列表使用了容器对象的原因。 但是,我也想使我的容器对象成为IEnumerable,但这意味着Protobuf-net将其抛出错误: 不支持嵌套或锯齿状的列表和数组 这是导致错误的列表结构示例: [ProtoContract] public class MyOuterList<T> { [ProtoMember(1)] readonly List<MyInnerList<T>> nestedData = new List<ObjectList<T>>(); } [ProtoContract] public class MyInnerList<T> : IEnumerable<T> { [ProtoMember(1)] private readonly List<T> data = new List<T>(); } 解决方法是从MyInnerList删除IEnumerable,但显然阻止了它的直接迭代。 是否有可以使用的像[ProtobufCustomObjectSoPleaseIgnoreIEnumerable]这样的偷偷摸摸的属性? 到目前为止,我想到的最好的替代方法是使用一个Enumerable属性,如下所示,但我担心该属性仍会再次投射回列表中。
  • Redis中嵌套结构的替代方案?(Alternatives to Nested Structures in Redis?)
    问题 我一直在遇到这样的情况:我要存储的信息比Redis的任何简单数据结构所能容纳的信息都要复杂。 我仍然想使用Redis,但我想知道人们在理想情况下是否希望使用嵌套结构使用任何标准替代方案? 回答1 您基本上有两种策略: 您可以序列化复杂对象并将其存储为字符串。 我们建议使用json或msgpack作为序列化格式。 这很容易从大多数客户端语言进行操作。 如果需要服务器端访问,则服务器端的Lua脚本可以轻松地对此类对象进行编码/解码,因为Redis是使用针对Lua的msgpack和json支持进行编译的。 您可以将对象拆分为不同的键。 除了存储user:id和该ID的复杂数据结构之外,您还可以存储几个键,例如user:id,user:id:address_list,user:id:document_lists等...如果您需要原子性,则对MULTI / EXEC块可用于保证数据一致性并汇总往返次数。 查看此答案中的一个简单示例: LPUSH命令将对从JSON初始化的记录起作用吗? 最后,Redis不是面向文档的数据库。 如果您确实有很多复杂的文档,那么MongoDB,ArangoDB,CouchDB,Couchbase等解决方案可能会更好地为您提供服务... 回答2 当您需要修改对象时,将复杂对象序列化为字符串并将字符串保存到Redis效率很低。 由于您必须将字符串取回客户端
  • python序列化原理与格式转换
    引言 本篇想从序列化开始,讲述python的xml、json以及protobuf文件格式,并实现xml到json以及json到protobuf之间格式的互转与xml增删改查操作。另外关于ujson与bjson等格式类型,会在最后进行总结。 序列化与反序列化 互联网的产生带来了机器间通讯的需求,而互联通讯的双方需要采用约定的协议,序列化和反序列化属于通讯协议的一部分。通讯协议往往采用分层模型,不同模型每层的功能定义以及颗粒度不同,例如:TCP/IP协议是一个四层协议,而OSI模型却是七层协议模型。在OSI七层协议模型中展现层(Presentation Layer)的主要功能是把应用层的对象转换成一段连续的二进制串,或者反过来,把二进制串转换成应用层的对象–这两个功能就是序列化和反序列化。一般而言,TCP/IP协议的应用层对应与OSI七层协议模型的应用层,展示层和会话层,所以序列化协议属于TCP/IP协议应用层的一部分。本文对序列化协议的讲解主要基于OSI七层协议模型。 上一段引用自美团2015年的 序列化和反序列化 . 不知道为啥看的人很少,但我觉得这篇文章概念都介绍得挺深的,我看得也受益匪浅,所以本篇的很多概念都会出自于这篇和几篇外文文献,我会在最后的参考文献里标注出来。那么经过上面这一段话,我们就能总结出序列化和反序列化的原理: 序列化:
  • 如何在 protobuf 消息中表示 UUID?(How do I represent a UUID in a protobuf message?)
    问题 我想将 UUID 附加到我的 protobuf 用户消息示例中的字段。 message User { // field containing id as UUID type required string email; optional string name; } 我知道 protobuf 消息还不支持 UUID 类型。 我读过最好的方法是使用 UUID 消息类型。 所以我猜我的 User 消息会导入我的 UUID 消息原型定义并将其用作字段类型,如下所示: import "myproject/UUID.proto"; message User { required UUID id; required string email; optional string name; } 我的问题是,UUID 消息会是什么样子,我将如何对其进行编码/解码? 我的目标是 Java/Scala 和 C# 兼容性。 回答1 您可能应该使用string或bytes来表示 UUID。 如果将 UUID 保持为人类可读的格式(例如"de305d54-75b4-431b-adb2-eb6b9e546014" )最方便,请使用string ,如果您存储 128 位原始值,则使用bytes 。 (如果您不确定,您可能需要string 。) 将值包装在称为UUID的消息类型中有助于使代码更具自文档性
  • C#通过socket发送结构对象(C# send structure objects through socket)
    问题 我已经阅读了一些 C# 客户端/服务器编程方面的内容。 我对这个过程非常熟悉,可以提出以下问题: 我如何通过 tcp/ip 而不仅仅是字符串传输结构对象? 我的应用程序是具有聊天功能的网络游戏。 因此,不仅仅是传输文本,我想采用一个具有两个字段的数据结构或类结构:i。 包类型 ii. 数据包类型的数据 我会在应用程序执行期间需要时传输它,并在接收端解码数据对象并将其放置在它所属的位置。 我不是在寻找代码,只是一些想法和搜索语句,我可以提供给谷歌,所以我会的; 有更好的了解。 我读过关于序列化/反序列化的内容,他是要走的路吗? 谢谢。 我已经检查了显示为相关主题的帖子,但仍需要进一步的指导。 回答1 最终是的:您正在谈论序列化。 这可以采用多种形式,尤其是在 .NET 中,但最终您需要在以下各项中进行选择: 文本与二进制; 直接二进制往往比文本小,因为它通常涉及较少的解析等; 文本(xml、json 等)在流中通常表示为 UTF8(尽管任何编码都是可能的)。 它们具有广泛的人类可读性,尽管更冗长,但通常可以很好地压缩。 合同与元数据; 基于契约的序列化器专注于表示数据——假设管道的另一端理解结构,但不假设它们共享一个实现。 这具有局限性,因为您不能突然引入一些完全出乎意料的子类,而是使其独立于平台。 相比之下,基于元数据的序列化程序在流上发送类型信息(即“这是一个My
  • Protoc Java 插件的依赖关系?(Dependencies for Protoc Java plugin?)
    问题 我正在尝试在 How to write a custom Protobuf CodeGenerator in Java 中制作工作示例。 当我尝试编译文件时 import com.google.protobuf.compiler.PluginProtos; import java.io.IOException; public class MyPlugin { public static void main(String[] args) throws IOException { CodeGenerator gen = new CodeGenerator(); PluginProtos.CodeGeneratorRequest codeGeneratorRequest = PluginProtos.CodeGeneratorRequest.parseFrom(System.in); codeGeneratorRequest.getProtoFileList().forEach(gen::handleFile); // get the response and do something with it //PluginProtos.CodeGeneratorResponse response = PluginProtos.CodeGeneratorResponse
  • Problems Deserializing Nested Dynamic Types with ProtoBuf-Net
    I am trying to deserialize an object that is wrapped in several layers of DynamicType = true, using ProtoBuf-Net r668. Using an older version of ProtoBuf-Net (v1), it will deserialize without a problem. With the latest version, however, it fails with ProtoBuf.ProtoException : Internal error; a key mismatch occurred [ProtoContract] private class A { [ProtoMember(1, DynamicType = true)] public object Body { get; set; } } [ProtoContract] private class B { [ProtoMember(1, DynamicType = true)] public object Body { get; set; } } [ProtoContract] private class C { [ProtoMember(1)] public string Name {
  • .NET 不能反序列化嵌套结构吗?(.NET can't deserialize nested structs?)
    问题 我遇到了让 C#(VS2008,Compact Framework,.NET 是 3.5 SP1 版)成功反序列化嵌套结构的问题。 当我在移动设备的模拟器上运行(我使用的是“Pocket PC 2003 Second Edition”模拟器)时,该问题仅出现在 CF 中,在我的 Windows 机器上运行的完全相同的代码没有相同的问题。 这是我的代码: public struct Fred { public string Name; } public struct Middle { public Fred[] Freds; } public struct Top { public Middle Middle; public Fred[] Freds; } public static void Test() { Top top = new Top(); top.Middle.Freds = new Fred[2]; top.Middle.Freds[0].Name = "Fred20"; top.Middle.Freds[1].Name = "Fred21"; top.Freds = new Fred[2]; top.Freds[0].Name = "Fred10"; top.Freds[1].Name = "Fred11"; StringBuilder sb = new
  • Serialize object[] with Protobuf-net
    I would like to serialize and deserialize some values stored in an object array. public class Sample { public object[] Data; } I know at run-time what types to expect in the array. In effect I want to treat Data inside of Sample as a message stream. Individually, I know I can use Serializer.NonGeneric.SerializeWithLengthPrefix to write each object out using a PrefixStyle.Base128 and make a Prefix->Type map for the Deserialise Type-Resolver. See What is protobuf-net SerializeWithLengthPrefix tag argument for? What I'm struggling with is actually getting protobuf-net to do that automatically for
  • 使用 Protobuf-net 序列化 object[](Serialize object[] with Protobuf-net)
    问题 我想序列化和反序列化存储在对象数组中的一些值。 public class Sample { public object[] Data; } 我在运行时知道数组中需要哪些类型。 实际上,我想将 Sample 中的 Data 视为消息流。 个别地,我知道我可以使用Serializer.NonGeneric.SerializeWithLengthPrefix使用PrefixStyle.Base128写出每个对象,并为反序列化类型解析器制作 Prefix->Type 映射。 请参阅什么是 protobuf-net SerializeWithLengthPrefix 标记参数? 我正在努力解决的问题实际上是让 protobuf-net 自动为我做这件事,然后将该行为嵌套在一个包含在内的消息中。 据我所知,流中的结果消息是完全有效的。 例如; 假设我有这个对象数组: new object[] { "Hello", 42, 0.3529321, true } 和标签映射 var typeToTag = new Dictionary<Type, int>() { {typeof (string), 1}, {typeof (int), 2}, {typeof (double), 3}, {typeof (bool), 4}, }
  • c++ protobuf 可能会遇到的坑
    1.发现存在内存泄露。 程序退出时记得调用: google::protobuf::ShutdownProtobufLibrary(); 这里一定是在程序退出时调用,如果调用后又使用了 protobuf 会出现异常,因为protobuf 中使用构造 会有创建指针,会存入 ShutdownData; 看ShutdownProtobufLibrary 源码: void ShutdownProtobufLibrary() { // This function should be called only once, but accepts multiple calls. static bool is_shutdown = false; if (!is_shutdown) { delete internal::ShutdownData::get(); is_shutdown = true; } } 解决方案: 定义成全局,全局只释放一次 struct A { ~A(){ google::protobuf::ShutdownProtobufLibrary() ; } }; A _globalProtobuf; 2.内存有异常: 可能是:protobuf 中的嵌套消息的使用临时变量例: string sn="1111"; string Algo="3333"; request.set_sn(sn)
  • Java:JSON-> Protobuf和反向转换(Java: JSON -> Protobuf & back conversion)
    问题 我有一个现有系统,该系统在GUI和服务器之间使用基于Protobuf的通信协议。 现在,我想添加一些持久性,但是目前protobuf消息已直接转换为第三方自定义对象。 有没有一种方法可以将原始消息转换为json ,然后可以将其持久化到数据库中。 注意:我不太喜欢将二进制protobuf写入数据库的想法,因为它有一天可能变得无法与较新版本向后兼容并以这种方式破坏系统。 回答1 如对类似问题的回答中所述,自v3.1.0起,这是ProtocolBuffers的受支持功能。 对于Java,请包括扩展模块com.google.protobuf:protobuf-java-util,并使用JsonFormat,如下所示: JsonFormat.parser().ignoringUnknownFields().merge(json, yourObjectBuilder); YourObject value = yourObjectBuilder.build(); 回答2 我们目前正在使用protobuf-java-format将Protobuf消息( Message任何子类)转换为JSON格式,以通过我们的Web API发送。 只需做: JsonFormat.printToString(protoMessage) 回答3 我不太喜欢将二进制protobuf写入数据库的想法
  • ProtoBuf在中C++使用介绍
    ProtoBuf 我们先来看看官方文档给出的定义和描述: protocol buffers 是一种语言无关、平台无关、可扩展的序列化结构数据的方法,它可用于(数据)通信协议、数据存储等。 Protocol Buffers 是一种灵活,高效,自动化机制的结构数据序列化方法-可类比 XML,但是比 XML 更小(3 ~ 10倍)、更快(20 ~ 100倍)、更为简单。 你可以定义数据的结构,然后使用特殊生成的源代码轻松的在各种数据流中使用各种语言进行编写和读取结构数据。你甚至可以更新数据结构,而不破坏由旧数据结构编译的已部署程序。 简单来讲, ProtoBuf 是结构数据序列化[1] 方法,可简单类比于 XML[2],其具有以下特点: 语言无关、平台无关。即 ProtoBuf 支持 Java、C++、Python 等多种语言,支持多个平台高效。即比 XML 更小(3 ~ 10倍)、更快(20 ~ 100倍)、更为简单扩展性、兼容性好。你可以更新数据结构,而不影响和破坏原有的旧程序 序列化[1]:将结构数据或对象转换成能够被存储和传输(例如网络传输)的格式,同时应当要保证这个序列化结果在之后(可能在另一个计算环境中)能够被重建回原来的结构数据或对象。 更为详尽的介绍可参阅 维基百科。类比于 XML[2]:这里主要指在数据通信和数据存储应用场景中序列化方面的类比,但个人认为 XML
  • Java中的序列化机制
    文章目录 序列化的意义市面上的序列化技术序列化接口Serializable、ExternalizableSerializableExternalizable serialVersionUID静态变量是否会被序列化?Transient关键字序列化技术的缺点写在最后 先抛出序列化相关几个面试问题,各位看看能否答得上来? Java序列化机制的意义是什么?你知道哪些序列化技术?如何自定义序列化内容?serialVersionUID有什么用?静态变量能否序列化?某个字段(比如密码字段)不想序列化的话,怎么办?序列化机制有什么缺点?Dubbo中的异常处理机制了解么?为什么要这么设计? 面试题是抛砖引玉,了解其背后原理才是目的,话不多说,发车了 序列化的意义 我们在内存中创建可复用的 Java 对象,但一般情况下,只有当 JVM 处于运行时,这些对象才可能存在,即,这些对象的生命周期不会比 JVM 的生命周期更长。但在现实应用中,就可能要求在 JVM 停止运行之后能够保存(持久化)指定的对象,比如将用户数据保存在磁盘中、数据库中,并在将来重新读取被保存的对象。 不同Java系统之间经常会有交换数据、通信的需求,但是网络中的数据传输都是以字节流的形式,因此发送方系统有必要把对象数据转化成字节流数据来在网络中传输,而接收方系统接收到字节流后再反序列化成Java对象。Dubbo这种RPC通信框架中
  • linux环境下protobuf的安装与使用
    零、最快捷的方式pip安装 (1)如下pip安装protobuf并制定版本 sudo yum install pip #安装pip pip install protobuf==2.5.0 #pip安装并制定protobuf的版本 sudo pip install --upgrade protobuf #更新protobuf版本 pip install gevent==1.4.0 #pip安装gevent并制定版本 pip install -i https://pypi.douban.com/simple/ locustio==0.11.0 #pip安装locust并制定版本 一、protobuf的下载安装 1、protobuf的下载:这里(next可找到更早版本)。此处下载的是protobuf-all-3.5.1.tar.gz。 2、安装准备:安装protobuf前确保以下软件都已经被安装。方法也很简单yum -y install XXXX即可。 #下面这些可能都是需要是事先安装的(如果后续安装出错往这里想想) autoconf automake libtool make g++ unzip 注1:可能会遇到一个蛋疼的问题。那就是执行make提示你要“yum install make”安装;指令安装语句又提示你“already install”,特别的蛋疼(见下图)。 解决办法
  • 深入Google ProtoBuf - 简介
    之前在网络通信和通用数据交换等应用场景中经常使用的技术是 JSON 或 XML,而在最近的开发中接触到了 Google 的 ProtoBuf。 在查阅相关资料学习 ProtoBuf 以及研读其源码之后,发现其在效率、兼容性等方面非常出色。在以后的项目技术选型中,尤其是网络通信、通用数据交换等场景应该会优先选择 ProtoBuf。 自己在学习 ProtoBuf 的过程中翻译了官方的主要文档,一来当然是在学习 ProtoBuf,二来是培养阅读英文文档的能力,三来是因为 Google 的文档?不存在的! 看完这些文档对 ProtoBuf 应该就有相当程度的了解了。 翻译文档见 [索引]文章索引,导航为翻译 - 技术 - ProtoBuf 官方文档。 但是官方文档更多的是作为查阅和权威参考,并不意味着看完官方文档就能立马理解其原理。 本文以及接下来的几篇文章会对 ProtoBuf 的编码、序列化、反序列化、反射等原理做一些详细介绍,同时也会尽量将这些原理表达的更为通俗易懂。 何为 ProtoBuf 我们先来看看官方文档给出的定义和描述: protocol buffers 是一种语言无关、平台无关、可扩展的序列化结构数据的方法,它可用于(数据)通信协议、数据存储等。Protocol Buffers 是一种灵活,高效,自动化机制的结构数据序列化方法-可类比 XML,但是比 XML 更小(3 ~