【工会神兽源码】【晓风源码】【技能交换 源码】protobuffer源码

2024-12-28 15:10:19 来源:like指标公式源码 分类:焦点

1.Google Protobuf 极速入门使用攻略 (C++版本)
2.Lua动态解析Protocol buffer
3.如何在eclipse中使用protocolbuf
4.Protocol Buffer详解(一)
5.protobuf 一种更小、更快、更高效的协议
6.Protobuf协议实现原理

protobuffer源码

Google Protobuf 极速入门使用攻略 (C++版本)

       要学习在C++中使用Google的Protocol Buffer,首先可以参考Git仓库:Teach-Myself-CPP/Protocol-buffer。Protocol Buffer作为一种灵活、高效且自动化的工会神兽源码数据序列化解决方案,对于处理数据结构的序列化/反序列化问题非常有用。

       当你需要在C++中处理数据结构时,有多种方法可选。然而,Protocol Buffer凭借其直观的定义方式脱颖而出。它的消息格式定义类似于C/C++中的类/结构,支持多种基础类型如int和string,以及嵌套类型,如PhoneType在PhoneNumber中,Person在AddressBook中。每个字段可以是required(不推荐,影响可移植性)、optional或repeated,分别对应必须存在、可选和可重复的字段值。

       安装Protocol Buffer后,通过命令行检查版本更新。然后,使用编译器将消息定义转换为cpp和h文件,如addressbook.pb.h和addressbook.pb.cc,它们会自动生成访问字段的getter和setter方法。

       在实际操作中,有一些通用的函数可以方便地进行消息的序列化和反序列化。例如,可以编写一个程序添加Person到磁盘文件,并反序列化文件中的数据到内存,展示详细信息。

       编译和运行程序通常通过Makefile或CMakeLists来完成,晓风源码但这里我们直接在命令行进行。接下来,尝试执行序列化和反序列化的步骤,完成整个过程。

Lua动态解析Protocol buffer

       Protocol Buffer是Google开源的一种数据存储和RPC格式,因其高效存储和低资源消耗而广泛应用于消息协议处理中。在游戏开发等领域,Protocol Buffer常作为前后端交互消息格式,利用其性能优势简化数据传输。

       为了适应手机端的动态更新需求,游戏开发者往往选择使用脚本语言,如Lua,来实现更灵活的协议设计。要将Protocol Buffer的动态解析融入Lua环境,实现协议描述文件修改后无需重新编译C++代码,关键在于设计一个能够动态加载和解析描述文件的解决方案。

       动态加载编译协议文件的目标是,在客户端启动后检测描述文件变动,更新至本地后即时加载新文件并使用新描述序列化或反序列化消息数据。这样实现后,客户端无需重新编译,仅需在Lua脚本中新增字段信息即可。

       实现这一目标需深入理解Protocol Buffer的动态编译原理。Protocol Buffer通过google::protobuf::compiler::Importer类动态编译未知描述文件,利用google::protobuf::compiler::MultiFileErrorCollector类搜集语法错误,google::protobuf::compiler::SourceTree类缓存加载的描述文件。动态编译时调用Importer对象的import方法即可实现。

       获取具体消息类的步骤中,利用Descriptor Pool的FindMessageTypeByName方法从描述文件中获取指定消息的Descriptor。通过Descriptor创建Message实例,最终目标是将Message转化为Lua table,利用Lua table的灵活性高效传递消息数据。

       将Protocol Buffer数据结构转化为Lua table,技能交换 源码主要依赖反射机制获取Message的所有Field,并通过遍历Lua table的key-value对进行数据传递。对于repeated字段,通过嵌套table形式处理重复的key值。序列化时,同样通过动态创建Message对象并填充Lua table数据,调用SerializeToString方法完成。

       在实现中需注意处理required字段的容错和提示信息,确保Lua脚本与C++层数据交互的正确性和稳定性。动态编译Protocol Buffer到Lua脚本的实现,有效提升了游戏开发的灵活性与效率,简化了前后端交互过程,为开发者提供了更为便捷的协议设计与维护手段。

如何在eclipse中使用protocolbuf

       Protocbuf 就是Protocol buffers,mxl一样在序列化数据结构时很灵活、高效和智能,但是它的优势在于定义文件更小,读取速度更快,使用更加简单。

       ä½¿ç”¨æ­¥éª¤ï¼š

       1 下载编译器和protocolbuff的jar包。

       2 把下载好的jar导入到eclipse。

       3 解压编译器压缩包,得到一个protoc.exe。

       4在eclipse中新建一个工程,名字比如叫做protocolbuffer,在该工程目录下,新建一个probuf(名字随意取)文件夹,用来装(.proto)文件的。同时把刚才解压得到的protoc.exe移动到该工程目录下面,并在path路径,配置该.exe的环境变量。

       5 Google官网,有个AddressBookProtos的例子,也就是哪个.proto文件,去原封不动复制下来,然后,放到刚才新建的工程中probuf的文件夹中,注意文件扩展名必须是.proto。

       6 用protoc.exe编译这个addressbook.proto文件,打开命令行,进入所建工程目录,执行如下命令 protoc –I=probuf/ --java_out=src probuf/addressbook.proto,(如果建的文件名和这个一样,直接原封不动,复制粘贴,执行即可),执行完毕即可得到java文件,路径是src\com\example\tutorial\AddressBookProtos.java。

       7在eclipse中看新建工程src下是否存在\com\example\tutorial\ AddressBookProtos.java,eclipse中没有导入成功,需要把他导入eclipse中,我是直接把src下此包直接剪切,然后放到桌面,然后直接在eclipse中src下粘贴就可以了。

       8编写测试java文件。Google同样有给出例子,其java源码在刚才放addressbook.proto文件夹中,有个LisPeople.java和一个AddPerson.java,直接复制粘贴进入你的eclipse中即可使用。

       9现在java源码都进入了eclipse中,并且无任何错误。首先执行添加人物信息,运行时却出错了,显示:Usage: AddPersonADDRESS_BOOK_FILE,这是因为,你用的eclipse执行的,而并非用命令来执行的,main方法中的,String[] args为空,应该注释掉main方法下紧跟着的if检查,并将所有的args[0]用一个string代替,比如”person.txt”,再次执行,就能添加了。

       æ‰©å±•ï¼š

       ProtocolBuf 的缺陷:那就是还不够成熟,且数据易读性很差。

Protocol Buffer详解(一)

       Protocol Buffer是一种支持多平台、多语言、可扩展的数据序列化机制,与XML相比,protobuf体积更小、速度更快、使用更简单,支持自定义数据结构。通过protobu编译器,可以生成特定语言的源代码,如C++、Java、Python,protoBuf对主流编程语言都提供了支持,使得序列化和反序列化变得非常方便。

       一、Message定义

       这里给出一个简单的例子,是一个搜索请求的message格式。

       上述例子中fields的种类都是数值型的(string和int),当然也可以指定更加复杂的coulmn命令源码fields,比如枚举类型enum,或者是嵌套的message类型。

       1、分配field编号

       上述例子中每个field都被分配了一个编号,这个编号是该field的唯一标识。需要注意的是,标识1-在编码时只占用一个字节,-占用两个字节,因此为了进一步优化程序,对于经常出现的element,建议使用1-作为其唯一标识;对于不经常使用的element,建议使用-。编号的范围是1-2^(-是系统预留的,不要使用)。

       2、field类型

       message中的field类型包含以下两种(proto3):

       (1)singular

       (2)repeated:该类型的field可以在message中重复使用(类似于数组),它们的顺序会被保存,通过索引进行检索,数值类型的repeated默认使用packed编码方式。

       3、多message结构

       在一个proto文件中可以定义多个protobuf。

       4、reserved field类型

       在开发过程中可能会涉及到对proto文件中message各个fields的修改,可能是更新、删除某个field及其表示,这样可能会导致调用的服务失败。其中一个防止这种问题的方式是,确保你要删除的field的标识(或是名字)是reserved,具体protobuf的编译器会决定未来这个field表示能否被使用。

       5、编译结果

       对于C++开发者来说,使用protoc编译一个proto文件之后,会生成pb.h和pb.cc两个文件。传世田野源码

       二、数值类型

       具体proto类型对应生成类中的类型可以参考官方文档。

       三、默认值

       对于string和byte类型,默认值为空;对于bool类型,默认值是false;对于数值类型,默认值是0;对于枚举类型,默认值是第一个枚举值,默认为0;对于message类型,默认值由编程语言决定;对于repeated field,默认值为空。

       四、枚举类型

       当采用枚举类型的之后,枚举中的值都是预先定义好的,对于上述例子,我们可以再额外增加一个枚举类型corpus,具体如下。

       通常枚举类型的第一个值初始化为0,而且在message中使用枚举类型,必须要给定一个为0的值,而且这个为0的值应该为第一个元素。

       也可以给不同的元素以相同的alias,但是需要指定option allow_alias = true;具体如下。

       除此之外枚举类型不仅可以定义在message内部,也可以定义在message外部,而且在不同message中可以重用enum。

       在更改枚举类型field时,为保证系统运行正常,同样可以指定reserved数字标识和命名。

       五、使用其他message类型

       1、同文件引用

       具体如下:

       2、不同文件引用

       引用其他proto文件中定义好的message类型,具体如下。

       有时我们会对引用的proto文件进行更改,比如将其内容移动到另外一个地方,这样我们就需要对调用方import路径进行更改,当调用方非常多的时候,这种方法是非常低效的,protobuf提供一种机制,我们可以在原有位置提供一个新位置proto文件的“副本”,通过使用import public表示来实现,具体可以参考如下例子。

       这时编译器就会在某些固定目录下查询import的proto文件(具体在命令行编译的时候,由-I/—proto_path指定),如果上述路径找不到,编译器会在调用路径进行查找。通常将—proto_path设置为项目的根目录,然后import的时候使用完整的路径名。

       3、使用proto2中的message类型

       proto2中的枚举类型无法直接使用。

       六、嵌套类型

       具体如下。

       在parent message之外调用嵌套的message可以用如下方式:SearchResponse.Result,嵌套结构可以更加复杂,具体如下:

       七、更新message类型

       当现有的message已经无法满足现有业务需要,你需要更新你的message类型以支持更复杂的业务,这就涉及到向后兼容的问题了,为保证已有服务不受影响,需要遵守以下的一些规定:

       1、不要更改已经存在的fields的数字标识

       2、如果添加新的field,利用旧代码序列化得到的message可以使用新的代码进行解析,你需要记住各个元素的默认值。新代码创建的field同样可以由旧代码进行加解析

       3、field可以被删除,但是需要保证其对应的数字标识不再被使用,你可以通过加前缀的方式来重新使用这个field name,或者指定数字标识为reserved来避免这种情况

       4、int、int、uint、uint、bool这些类型都是互相兼容的,并不会影响前向、后向兼容性

       5、sint和sint之间是互相兼容的,但是和其他数字类型是不兼容的

       6、string和bytes是互相兼容的,只要使用的是UTF-8编码

       7、如果byte包含message的编码版本,则嵌套的message和bytes兼容

       8、flexed兼容sfixed,fixed,sfixed

       9、enum兼容 int, uint, int, and uint。对于这个值在转化时,不同语言的客户端处理方式会有所不同

       感兴趣的小伙伴可以关注公众号:独立团丶

protobuf 一种更小、更快、更高效的协议

       Protocol Buffers,简称protobuf,是由Google开发的一种数据格式,类似于XML,能够将结构化数据序列化,适用于数据存储、通信协议等领域。它不依赖于语言和平台,且可扩展性极强。

       protobuf仓库地址为:github.com/protocolbuff...

       protobuf支持多种编程语言,例如C++、Java、Python等。然而,它并不支持C语言,因此出现了第三方的protobuf-c。

       protobuf-c仓库地址为:github.com/protobuf-c/p...

       要使用基于C语言的protobuf,首先需要安装protobuf与protobuf-c。

       在Ubuntu下安装protobuf的方法如下:

       首先,需要安装依赖工具,然后依次输入以下命令下载、编译、安装protobuf:

       其中,执行./autogen.sh命令是为了生成configure配置脚本,执行configure可生成Makefile文件,执行make进行编译,执行sudo make install命令进行安装,执行sudo ldconfig命令让动态链接库为系统所共享。

       同样,protobuf-c也需要依赖于pkg-config,输入以下命令进行安装:

       然后输入以下命令下载、编译、安装protobuf-c:

       按照以上方式安装,protobuf与protobuf-c默认安装在/usr/local路径下。

       在安装过程中可能会遇到各种错误,遇到错误时,仔细查看错误描述以及本篇文章的安装步骤,看是否遗漏了哪一步。

       protobuf的核心是一个.proto文件,我们自定义一个.proto文件来创建我们的协议数据,然后使用protoc-c工具编译生成C代码,生成两个文件:一个头文件、一个源文件。

       例如,我们创建一个student.proto文件:

       其中,syntax为语法版本,有proto2、proto3两个版本,我们使用proto2。与C语言类似,.proto也规定了一些数据格式,如proto2的数据类型有:double、float、int、uint、string等。

       本例中,message为关键字,修饰的Student会对应生成我们C中的Student结构体。其中required为前缀修饰,表明该字段是必填字段。还有其他两个修饰关键字:

       使用protoc-c工具编译student.proto文件的命令:

       此时编译会生成student.pb-c.c、student.pb-c.h两个文件。我们看看student.pb-c.h里面有什么:

       可以看到,student.pb-c.h里生成了一个协议数据结构体与操作该结构体的一些接口,包括组包与解包接口,对应的student.pb-c.c里就是这些接口对应的实现。

       编写我们的student.c测试demo:

       demo很简单,组包就是构造一个协议数据结构体,调用pack组包接口往buffer中扔数据;解包正好是反过来,从buffer中拿数据放到结构体里。

       编译命令:

       加上-lprotobuf-c参数链接动态链接库protobuf-c.so,因为前面安装操作的时候有使用ldconfig命令了,所以这里不需要指定动态库路径,否则需要指定。

       编译运行:

       如果运行时报错:找不到动态库,可输入如下命令导出动态库:

Protobuf协议实现原理

        protobuf 是Google开源的一款支持跨平台、语言中立的结构化数据描述和高性能序列化协议,此协议完全基于二进制,所以性能要远远高于JSON/XML。由于出色的传输性能所以常见于微服务之间的通讯,其中最为著名的是Google开源的 gRPC 框架。

        那么protobuf是如何实现高性能的,又是如何实现数据的编码和解码的呢?

        基于bits的数据存储方式(Base Varints)

        Varint 是一种紧凑的表示数字的方法。它用一个或多个字节来表示一个数字,值越小的数字使用越少的字节数。这能减少用来表示数字的字节数。

        比如对于 int 类型的数字,一般需要 4 个 byte 来表示。但是采用 Varint,对于很小的 int 类型的数字,则可以用 1 个 byte 来表示。当然凡事都有好的也有不好的一面,采用 Varint 表示法,大的数字则需要 5 个 byte 来表示。从统计的角度来说,一般不会所有的消息中的数字都是大数,因此大多数情况下,采用 Varint 后,可以用更少的字节数来表示数字信息

        Varint 中的每个 byte 的最高位 bit 有特殊的含义,如果该位为 1,表示后续的 byte 也是该数字的一部分,如果该位为 0,则结束。其他的 7 个 bit 都用来表示数字。因此小于 的数字都可以用一个 byte 表示。大于 的数字,比如 ,会用两个字节来表示: 。

        另外如果从数据大小角度来看,这种表示方式比实现的数据多了一个bit, 所以其实际传输大小就多%(1/7 = 0.)。

        数字1表示方式:

        对于小的数据比较好理解,正常情况下1的二进制是 ,使用bits表示的话,首位结束标识位也是0,所以两者结果是一样的 0。

        数字 表示方式:

        <figcaption></figcaption>

        这个有点不太好理解了,这是因为原本用一个字节(8bit)就可以表示,但由于使用bits表示方法,需要对每个字节的最高位添加一个结束标识位来表示,所以一个字节已经不够用了,需要占用两个字节来表示,其中两个字节最高位都是结束标识位。

        如果正向推算的话,我们知道数字的二进制值 1 ,用两个字节表示完整值则为

        # 二进制

        _ _ # 二进制每个字节的最高位向左移动一个位置,放入结束标识位

01# 转换为bits方式,1:结束,0:未结束

10# 转换为 小端字节序 , 低字节在前,高字节在后

        注意这里是先添加结束标识符,然后再转为小端字节序。

        消息经过序列化后会成为一个二进制数据流,该流中的数据为一系列的 Key-Value 对。如下图所示:

        采用这种 Key-Pair 结构无需使用分隔符来分割不同的 Field。对于可选的 Field,如果消息中不存在该 field,那么在最终的 Message Buffer 中就没有该 field,这些特性都有助于节约消息本身的大小。

        Key 用来标识具体的 field,在解包的时候,客户端创建一个结构对象,Protocol Buffer 从数据流中读取并反序列化数据,并根据 Key 就可以知道相应的 Value 应该对应于结构体中的哪一个 field。

        而Key也是由以下两部分组成

        Key 的定义如下:

        | 1 | (field_number << 3) | wire_type |

        可以看到 Key 由两部分组成。第一部分是 field_number。第二部分为 wire_type。表示 Value 的传输类型。

        一个字节的低3位表示数据类型,其它位则表示字段序号。

        Wire Type 可能的类型如下表所示:

        在我们的例子当中,field id 所采用的数据类型为 int,因此对应的 wire type 为 0。细心的读者或许会看到在 Type 0 所能表示的数据类型中有 int 和 sint 这两个非常类似的数据类型。Google Protocol Buffer 区别它们的主要意图也是为了减少 encoding 后的字节数。

        每个数据头同样采用bits方式,一般1个字节就足够了,

        本例中字段a 的序号是1

        如上创建了 Test1 的结构并且把 a 的值设为 2,序列化后的二进制数据为

00

        Key 部分是

        value 部分是 , 其中字节最高位是结束标识位,即进制的2,我们在转换的时候统一将符号位转为0即可。

        协议规定数据头的低3位表示wire_type, 其它字段表示字段序号field_number,因此

       

        _ # 去掉结束标识符位

        _ # 表示数据类型, 这里是Varint

        _ # 这四位表示字段序号

        /linux/l-cn-gpb/

        原文: /archives/

Protobuf在UE5中的简单使用说明

       Protocol Buffer(简称 Protobuf)是 Google 提供的一种数据存储格式,用于结构化数据的高效序列化。它支持跨多种编程语言通信,通过单一标准协议定义数据格式,自动生成语言特定的包。

       步骤1:创建proto文件。以登录消息`login.proto`为例,文件中定义了消息结构和消息ID。

       步骤2:生成对应C++文件。通过批处理脚本在`client\Plugins\BLProtobuf\Source\BLProtobuf\protoc_tools`目录下双击,即可自动生成并拷贝到`client\Source\ProjectMeta\Proto`目录。

       步骤3:注册包反射。需要在头文件中提供消息ID和消息类名,之后在回调函数中调用RegisterPackage,完成包注册。

       步骤4:实现回调函数。确保RegisterPackage调用在回调函数之后,简单地将其加入到每个回调函数文件的末尾。

       开发建议:设计子系统,如登录子系统,包含发起登录、登录回调接口。注册等接口可在子系统中扩展。

       具体C++实现代码如下,其中省略了详细代码示例,建议根据实际情况调整并添加到对应文件中。

本文地址:http://abssuliao.net/news/03a575694240.html 欢迎转发