当前位置: 首页 > 后端技术 > Python

PythonGoogleProtocolBuffer详解

时间:2023-03-26 18:10:56 Python

本文主要介绍如何在Python语言中使用GoogleProtocolBuffer(以下简称PB),包括以下几个部分:为什么要使用PB?安装GooglePB自定义.proto文件编译.proto文件解析目标py文件序列化反序列化更复杂的Message动态编译为什么要用PB?PB(ProtocolBuffer)是Google开发的结构化数据交换格式,作为腾讯云日志服务的标准写入格式。因此,在写入日志数据之前,需要将原始日志数据序列化为PB数据流,然后通过API写入服务器。但是在每个终端程序中操作PB格式不方便,所以需要在终端类和日志服务之间加一层PB转换层。当然PB格式也有自己的优势,主要是简单快捷。具体测试结果见谷歌序列化基准分析安装谷歌PB如果你想在Python中使用PB,你需要安装PB编译器protoc来编译你的.proto文件,安装方法如下如下:下载最新的protobuf发布包并安装。当前版本是3.5.1。安装步骤如下wgethttps://github.com/google/protobuf/releases/download/v3.5.1/protobuf-all-3.5.1.tar.gztarxvfzprotobuf-all-3.5.1.tar.gzcdprotobuf-3.5.1/./configure--prefix=/usrmakemakecheckmakeinstallcheck所有步骤都通过则编译通过。继续安装protobuf的python模块cd./pythonpythonsetup.pybuildpythonsetup.pytestpythonsetup.pyinstall安装完成verifyprotoc命令root@ubuntu:~#protoc--versionlibprotoc3.5.1默认安装位置protobuf是/usr/local,/usr/local/lib不在Ubuntu系统默认的LD_LIBRARY_PATH中。如果在Ubuntu系统中配置时没有指定安装路径为/usr,会出现如下错误protoc:errorwhileloadingsharedlibraries:libprotoc.so.8:cannotopensharedobjectfile:Nosuchfileordirectory可以解决使用ldconfig命令,参考Protobufcannotfindsharedlibraries,这个错误在安装包的README中有提到。当然重新安装也可以验证Python模块是否安装正确。在python解释器中导入google.protobuf。如果上面import没有报错,说明安装正常。自定义.proto文件首先我们需要编写一个proto文件来定义我们程序中需要处理的结构化数据。在protobuf术语中,结构化数据称为Message。proto文件非常类似于java或C++语言的数据定义。proto示例文件cls.Log.proto如下:syntax="proto2";packagecls;messageLog{optionaluint64time=1;//UNIX时间格式要求stringtopic_id=2;requiredstringcontent=3;}在proto文件的开头是一个包声明,以帮助防止不同项目中的命名冲突。在Python中,包通常是由目录结构决定的,所以这个.proto文件定义的包在实际的Python代码中是没有作用的。不过按照官方的建议是坚持声明这个声明,主要作用是防止PB命名空间中的名称冲突。包名cls,定义了一个消息Log,有3个成员。各成员含义如下:字段名,类型,位置,必须表示timeuint64body,无日志时间,不指定则使用服务器收到请求时的时间topic_idstringbody为日志报告日志主题idcontentstringbody为日志内容.一个好习惯是认真对待proto文件的文件名。例如,设置命名规则为:packageName.MessageName.proto编译.proto文件,使用编译器protoc直接编译。需要指定源文件路径和目标文件路径SRC_DIR=/tmp/src_dirDST_DIR=/tmp/dst_dirprotoc-I=$SRC_DIR--python_out=$DST_DIR$SRC_DIR/cls.Log.proto使用--python_out选项生成一个Python类。如果要生成C++类,请使用--cpp_out选项来解析目标py文件。目标文件夹中生成的文件目录对应如下:root@ubuntu:/tmp/dst_dir#tree.└──cls└──Log_pb2.py1目录,1个文件Log_pb2.py文件内容如下(不允许编辑):#由协议缓冲区编译器生成。不要编辑!#source:cls.Log.protoimportsys_b=sys.version_info[0]<3and(lambdax:x)or(lambdax:x.encode('latin1'))fromgoogle.protobufimportdescriptoras_descriptorfromgoogle.protobuf将消息导入为_messagefromgoogle.protobuf将反射导入为_reflectionfromgoogle.protobuf将symbol_database导入为_symbol_databasefromgoogle.protobuf导入descriptor_pb2#@@protoc_insertion_point(imports)_sym_db=_symbol_database.Default()DESCRIPTOR=_descriptor.FileDescriptor(name='cls.Log.proto',package='cls',syntax='proto2',serialized_pb=_b('\n\rcls.Log.proto\x12\x03\x63ls\"6\n\x03Log\x12\x0c\n\x04time\x18\x01\x01(\x04\x12\x10\n\x08topic_id\x18\x02\x02(\t\x12\x0f\n\x07\x63ontent\x18\x03\x02(\t'))_LOG=_descriptor.Descriptor(name='Log',full_name='cls.Log',filename=None,file=DESCRIPTOR,containing_type=None,fields=[_descriptor.FieldDescriptor(name='time',full_name='cls.Log.time',index=0,number=1,type=4,cpp_type=4,label=1,has_default_value=False,default_value=0,message_type=None,enum_type=None,containing_type=None,is_extension=False,extension_scope=None,options=None,file=DESCRIPTOR),_descriptor.FieldDescriptor(名称='topic_id',full_name='cls.Log.topic_id',index=1,number=2,type=9,cpp_type=9,label=2,has_default_value=False,default_value=_b("").decode('utf-8'),message_type=None,enum_type=None,containing_type=None,is_extension=False,extension_scope=None,选项s=None,file=DESCRIPTOR),_descriptor.FieldDescriptor(name='content',full_name='cls.Log.content',index=2,number=3,type=9,cpp_type=9,label=2,has_default_value=False,default_value=_b("").decode('utf-8'),message_type=None,enum_type=None,containing_type=None,is_extension=False,extension_scope=None,options=None,file=DESCRIPTOR),],extensions=[],nested_types=[],enum_types=[],options=None,is_extendable=False,syntax='proto2',extension_ranges=[],oneofs=[],serialized_start=22,serialized_end=76,)DESCRIPTOR.message_types_by_name['Log']=_LOG_sym_db.RegisterFileDescriptor(DESCRIPTOR)Log=_reflection.GeneratedProtocolMessageType('Log',(_message.Message,),dict(DESCRIPTOR=_LOG,__module__='cls.Log_opepb2'#@@protoc_insertion_point(:cls.Log)))_sym_db.RegisterMessage(Log)#@@protoc_insertion_point(module_scope)pb生成的py文件源码解析暂时搁置,请参考数据序列化和反序列化中附件#!/usr/bin/envpython#-*-coding:utf-8-*-"""创建于1/30/184:23PM@author:ChenLiang@function:pbtest"""importsysreload(sys)sys.setdefaultencoding('utf-8')importLog_pb2importjsondefserialize_to_string(msg_obj):ret_str=msg_obj.SerializeToString()返回ret_strdefparse_from_string(s):log=Log_pb2.Log()log.ParseFromString(s)returnlogif__name__=='__main__':#serialize_to_stringcontent_dict={"live_id":"1239182389648923","identify":"zxc_unique"}tencent_log=Log_pb2.Log()tencent_log.time=1510109254tencent_log.topic_id="JohnDoe"tencent_log.content=json.dumpret_s=serialize_to_string(tencent_log)print(type(ret_s))print(ret_s)#parse_from_stringlog_obj=parse_from_string(ret_s)print(log_obj)关键操作是消息对象的写入和读取以及序列化函数SerializeToString和反序列化到此为止,我们有只给出一个简单的上传日志的例子。在实际应用中,人们往往需要定义更复杂的Messages。我们使用“复杂”这个词,不仅仅是指在数量上更多的字段或更多类型的字段,而是指更复杂的数据结构:消息嵌套ImportMessage下面介绍消息嵌套和嵌套嵌套是一个神奇的概念。一旦有了嵌套的能力,表达信息的能力就会非常强大。具体嵌套Message的例子如下messagePerson{requiredstringname=1;要求int32id=2;//此人的唯一ID号。可选字符串email=3;枚举PhoneType{MOBILE=0;家=1;工作=2;}messagePhoneNumber{需要的字符串number=1;可选PhoneType类型=2[默认=HOME];}重复PhoneNumberphone=4;在MessagePerson中,定义了嵌套的消息PhoneNumber,用于定义Person消息电话域。这允许人们定义更复杂的数据结构。ImportMessage在一个.proto文件中,还可以使用Import关键字引入其他.proto文件中定义的消息,可以称为ImportMessage,或DependencyMessage。importmessage的具体例子如下:importcommon.header;消息youMsg{需要common.info_headerheader=1;必需的字符串youPrivateData=2;其中,common.info_header定义在common.header包中。ImportMessage主要是为了提供一种方便的代码管理机制,类似于C语言中的头文件。可以在一个package中定义一些publicMessages,然后在其他.proto文件中import这个package,然后使用其中的message定义。GoogleProtocolBuffer可以很好地支持嵌套Message和导入Message,这使得定义复杂数据结构的工作变得非常轻松愉快。动态编译一般使用Protobuf的人都会先编写.proto文件,然后使用Protobuf编译器生成目标语言需要的源代码文件。使用应用程序编译这些生成的代码。但在某些情况下,人们无法提前知道.proto文件,需要动态处理一些未知的.proto文件。比如一般的消息转发中间件,是无法预测需要处理什么样的消息的。这需要动态编译.proto文件并使用其中的Message。详细解释参见:GoogleProtocolBuffer使用及原理参考:https://developers.google.com...https://developers.google.com...http://hzy3774.iteye.com/blog...https://github.com/google/pro...https://github.com/google/pro...https://blog.csdn.net/losophy...https://www.ibm.com/developer...https://github.com/google/pro...https://github.com/google/pro...PythonGoogle协议缓冲区:https://developers.google。com。..记得给我点赞哦!对计算机各个方向的视频课程和电子书,从入门、进阶、实用进行了认真梳理,并按照目录进行合理分类。你总能找到你需要的学习资料。你在等什么?立即关注并下载!!!念念不忘,必有回响,朋友们,请点个赞,万分感谢。我是职场亮哥,四年工作经验的YY高级软件工程师,拒绝当领导的斜杠程序员。听我说,我进步很大。如果有幸帮到你,请给我一个【点赞】,给我一个关注,如能评论鼓励,将不胜感激。职场凉阁文章列表:更多文章我的所有文章和回答均与版权保护平台合作,版权归职场凉阁所有。未经授权转载必究!