ProtoBuf 源码简析


ProtoBuf项目描述:
  Google Protocol Buffer简称protobuf,为高效的二进制序列化/反序列化协议(一般为google内部使用),不同于xml、json等,其更小巧、高效;avro、thrift等;
其可用于网络协议、数据存储等语言无关、平台无关、可扩展的序列化结构数据格式。只要按照特定条件可支持向前、向后兼容;目前提供了C++、Java、Python 
三种语言的 API,这样各语言可以相互序列化和反序列化数据信息(事实上也可以自定义实现其他语言的API接口)。
    
   在使用中,用户可根据自定义或引入数据结构(Message)文件*.proto;此后通过编译器protoc.exe编译该描述文件为指定语言的操作接口,而后将产生的操作接口文件
和libprotobuf.lib添加入项目中进行数据序列化和反序列化操作即可,产生的序列化后的信息可读性很差,此外反序列化也必须知道对应的数据结构描述文件*.proto,
否则无法正确地反序列化,也不再有意义,相对xml,json无法直接插入或修改数据信息内容;

  以下仅对C++相关进行分析;
  项目工程:
        gtest:google 白盒测试开源项目,主要用于单元测试,后面的gtest_main、tests项目;
        gtest_main:简单的对main函数以及testing::InitGoogleTest(&argc, argv);RUN_ALL_TESTS();封装的lib,这样其他测试工程只需要包含引入该库并集中精力在
        测试用例上;
        libprotobuf:protobuf基础工程库,主要实现;
        libprotobuf-lite:
        libprotobufc:对应protobuf的编译器封装为库,以支持c++、java、python语言对*.proto文件的编译为相应的接口API;
        lite-test:
        protoc:简单的控制台实现的protoc编译器,该编译器通过命令行参数传递对应的*.proto文件和编译输出接口API选项;依赖于libprotobuf、libprotobufc;
        test_plugin:
        tests:
        
    *.proto数据描述文件说明:
    
    protoc编译器命令行参数说明和生成文件API文件名说明:
    
    *.proto 文件编译后为*.pb.h以及*.pb.cc;
项目内容简析:

  libprotobuf:protobuf基础工程库,内部主要实现编码和解码等相关操作。 config.h:配置相关,事实上为声明宏hash_map、hash_set头文件以及编译宏HAVE_HASH_SET、HAVE_HASH_MAP; template_util.h :模板元编程相关的工具,模板、函数;主要包括: integral_constant、if_、type_equals_、and_、or_、true_、false_; type_traits.h :在template_util.h的基础上,定义了一系列类型特征萃取相关的模板类或函数如:is_xxx,has_xxx,remove_xxx; common.h:内部使用公共函数、基本类型,全局常量、用于当前库的工具模板辅助函数; GOOGLE_DISALLOW_EVIL_CONSTRUCTORS:不允许赋值拷贝宏; LIBPROTOBUF_EXPORT
/LIBPROTOC_EXPORT:导入导出宏; 一系列标识库版本的宏、常量,格式:major * 10^6 + minor * 10^3 + micro,如:2005000; VersionString:整形转化为版本字符串;格式:major.minor.micro,如:2.5.0 VerifyVersion:版本兼容性检定函数; 重声明基本类型,便于统一处理以及定义了几种类型静态变量最大最小值; GOOGLE_ARRAYSIZE:安全的获取数组元素个数(若未对齐,则会提示除0警告); implicit_cast:隐式转换模板;类似于static_cast、const_cast的安全版本; down_cast:向下转换,由父类指针对象转型为某个子类,内部使用static_cast转型,在调试模式下时使用dynamic_cast进行验证; CompileAssert:编译时断言,结合GOOGLE_COMPILE_ASSERT宏,内部通过msg[-1或1]确定是否可通过编译,可能对浮点数0.0之类的存在歧义; scoped_ptr/scoped_array:指针包装,智能指针; LogLevel:日志级别,提供INFO、WARN、ERROR、FATAL几种严重级别; LogMessage:消息日志,记录、操作消息; LogMessage:构造函数传参为日志级别、文件名称、所在行; 重载多个版本operator<<; Finish:完成操作,内部若为非FATAL日志,则将调用InitLogSilencerCountOnce,此外若无静默者·则调用log_handler_处理该日志, 默认调用接口为DefaultLogHandler(默认向stderr输出,格式“[libprotobuf level filename:line] message ”),此外若为FATAL日志, 则根据是否使用异常抛出FatalException类型对象异常或调用abort终止进程; level_:日志级别; filename_:文件名称; line_:所在行; message_:消息内容; LogFinisher:log日志完成者,实现了operator=,内部调用LogMessage的Finish函数; GOOGLE_LOG:log宏,封装LogFinisher作为工具封装; GOOGLE_LOG_IF:条件log宏; GOOGLE_CHECK_XXX:一系列检测宏,内部调用GOOGLE_LOG_IF(FATAL,...); CheckNotNull:非NULL检测以及宏GOOGLE_CHECK_NOTNULL; debug模式下的GOOGLE_DCHECK_XXX调试宏; SetLogHandler:设置日志控制器log_handler_,若参数为NULL则设置为NullLogHandler,其不处理日志信息, LogSilencer:日志静默者,跳过非FATAL日志,使得log_handler_控制器不处理日志;使用时可直接在某个函数点创建临时对象即可,在作用 域内,产生的日志信息将会被“吸收”;作用域外则恢复到正常的日志处理; Closure:称为关闭、终止的基类,内部只提供了纯虚函数Run; FunctionClosureXXX/MethodClosureXXX:继承于Closure类,实现Run内部调用传入的函数并根据参数删除释放当前本类对象;前者主要传入普通 或类的静态成员函数,后者主要处理类对象以及相应类的成员函数;目前仅实现了支持0,1,2个参数的继承类; NewCallback/NewPermanentCallback:分别重载了对应不同参数类型的模板帮助函数,内部通过new创建FunctionClosureXXX/MethodClosureXXX; 前者创建了调用Run会自动删除对象;后者为永久对象,用户可根据需要某个时刻delete该对象; DoNothing:空函数操作; Mutex:锁,通过IMPL技巧实现,内部利用临界区实现锁机制,此外AssertHeld函数用以在调试模式下检测当前线程下是否为获取到锁的线程; MutexLock:自动锁,对Mutex的封装,此外重声明锁ReaderMutexLock、WriterMutexLock; MutexLockMaybe:同MutexLock,但更安全; IsStructurallyValidUTF8:检测是否包含UTF-8的字符编码; ghtonl:主机字节序转化为网络字节序,同htonl; ShutdownProtobufLibrary:关闭protobuf库,主要为执行关闭操作函数集vector<void (*)()>的shutdown_functions内容,释放shutdown_functions、 shutdown_functions_mutex锁对象; OnShutdown:注册关闭库时被调用的函数,添加至shutdown_functions; FatalException:继承于std::exception,构造函数提供文件名称、所在行、消息内容,并添加filename、line、message操作方便获取相应成员变量值; platform_macros.h:跨平台相关的宏定义; atomicops.h:提供跨平台的原子操作,内部实现根据相应平台编译相应接口的实现,以下以X86 msvc编译器为例,将采用atomicops_internals_x86_msvc的实现; Atomic32/AtomicWord:原子类型重声明; NoBarrier_CompareAndSwap:内部调用InterlockedCompareExchange,实现原子的比较交换操作; NoBarrier_AtomicExchange:内部调用InterlockedExchange,实现原子指定值操作; NoBarrier_AtomicIncrement:内部调用InterlockedExchangeAdd,实现原子加操作,累加的数值为参数的2倍值; Barrier_AtomicIncrement:同NoBarrier_AtomicIncrement;、 Acquire_CompareAndSwap:事实上内部调用NoBarrier_CompareAndSwap; Release_CompareAndSwap:事实上内部调用NoBarrier_CompareAndSwap; MemoryBarrier:内部调用MemoryBarrier,实现硬件防护,以防止CPU或编译器乱序执行; NoBarrier_Store:非防护设置,参数指针对象ptr设置值为value; Acquire_Store:内部调用NoBarrier_AtomicExchange; Release_Store:同NoBarrier_Store; NoBarrier_Load:获取当前参数值; Acquire_Load:获取临时参数值; Release_Load:获取MemoryBarrier防护后的当前参数值; once.h:主要封装初始化一次的操作; 通过定义GOOGLE_PROTOBUF_DECLARE_ONCE宏原子变量以及初始化函数,当调用GoogleOnceInit时实现执行一次初始化函数; 示例:void Init();GOOGLE_PROTOBUF_DECLARE_ONCE(once_init);void InitOnce(){GoogleOnceInit(&once_init,&Init);};任何多次调用InitOnce函数只会最终 调用Init初始化函数一次; 内部定义了三种原子状态:未初始化ONCE_STATE_UNINITIALIZED、正在执行初始化ONCE_STATE_EXECUTING_CLOSURE、已完成初始化ONCE_STATE_DONE; GoogleOnceInit:初始化一次函数,参数分别为原子、初始化函数;提供无参版本和重载模板一个参数的版本;函数内部调用Acquire_Load获取原子状态,此后根据 状态处理创建FunctionClosure0执行GoogleOnceInitImpl; GoogleOnceInitImpl:内部处理原子状态并处理多线程下执行流程;若未初始化则设置原子为正在初始化并执行FunctionClosure0的Run函数,执行完成后设置原子 为已完成初始化状态;若其他线程进入时,若此时仍为正在执行初始化,则循环查询原子状态并调用SchedYield放弃CPU时间片; strutil.h:字符、字符串工具函数; ascii_isalnum:ASCII码是否为a~z或A~Z或0~9的字符; ascii_isdigit:ASCII码是否为数字字符; HasPrefixString:原始字符串是否有指定的前缀字符串; StripPrefixString:获取剥去原始字符串中的指定前缀的字符串,否则为原始字符串; HasSuffixString:原始字符串是否有指定的后缀字符串; StripSuffixString:获取剥去原始字符串中的指定后缀的字符串,否则为原始字符串; StripString:查找指定字符串s中被匹配的模式字符串remove中出现的位置,并替换为字符replacewith;内部调用strpbrk实现查找匹配; LowerString:字符串小写化; UpperString:字符串大写化; StringReplace:相对StripString,其实现字符串分片替换为新的字符串,若参数replace_all为true,则全部替换,否则只替换第一次出现的; SplitStringUsing:对给定的模式字符串delim,匹配原始字符串full,并拆分至vector<string>* res中; SplitStringAllowEmpty:相对SplitStringUsing,其允许空原始字符串和传回空字符串; JoinStrings:提供两个版本,合并字符串和分隔符字符串合并,字符串间为分隔符字符串组合为返回字符串; UnescapeCEscapeSequences:转化字符串各字符为相应的ASCII码; UnescapeCEscapeString:同UnescapeCEscapeSequences; CEscapeString/CEscape:转化字符串,保存部分标识(目前\n, \r, \t, ", ', \以及不可打印的字符将被隐藏(保护)); 字符串与数值间的相互转化; strto32/strtou32/strto64/strtou64:字符串转数值(内部调用strtoXXX系列函数); FastXXXToBuffer:系列函数,数值转化为字符串,字符串右对齐; FastXXXToBufferLeft:系列函数,数值转化为字符串,字符串左对齐; SimpleItoa:重载版本,整型数值转字符串,参数为有符号时内部调用FastXXXToBuffer,无符号时调用FastXXXToBufferLeft; SimpleDtoa/SimpleFtoa:分别为双精度、单精度浮点转字符串; DoubleToBuffer/FloatToBuffer:双精度、单精度浮点转字符串; 目前控制字符串转化最大长度为kDoubleToBufferSize(32位),kFloatToBufferSize(24位); NoLocaleStrtod:无区域化字符串转双精度浮点数;类似于strtod; stl_util.h:STL相关的部分辅助工具、函数; STLDeleteContainerPointers:模板实现,删除释放容器内指针对象资源,参数为容器收尾迭代器对象; STLStringResizeUninitialized:重置容器大小,针对string容器,内部调用resize; string_as_array:string字符串当前array使用,内部取string的begin地址位置;使用时示例;string str;string_as_array(&str)[i]; 个人认为与string的operator[]等价; STLDeleteElements:模板实现,内部调用STLDeleteContainerPointers,且调用容器对象的clear接口;释放容器内对象资源且清空容器; STLDeleteValues:模板实现,一般用在map或pair对的容器参数,以释放容器value值对应的对象内容,并调用clear清空容器; hash.h:封装实现内部使用的hash_map和hash_set; hash<key>:模板类,继承于std::hash_compare<key>; CstringLess:函数对象(仿函数),作为hash_compare<const char*, CstringLess>的operator<比较操作模板参数,其仅支持const char*参数(内部通过strcmp比较); hash<const char*>:hash模板特化版本,继承于std::hash_compare<const char*, CstringLess>; hash_map/hash_set:分别继承与hash_map/hash_set;对于非MSVC编译器,则采用的自己的实现,此外对hash<const char*>则使用result = 5 * result + *str; 循环叠加的方式处理; hash<string>:hash模板特化版本; hash<pair<First, Second> >:针对pair的版本; streq:仿函数,实现比较const char*字符串相等操作,内部调用strcmp; maputil.h:map或hash_map辅助工具、函数,以下的map代表map或hash_map; FindWithDefault:查找map容器中指定key的value值,否则返回提供的默认值value; FindOrNull:查找map容器中指定key的value值地址,否则返回NULL; FindOrDie:查找map容器中指定key的value值地址,否则抛出FatalException异常或终止进程; FindPtrOrNull:查找map容器中指定key的value值,否则返回0; InsertOrUpdate:若map容器存在对应的key则更新,否则插入元素,返回值false表示更新,true为插入; InsertIfNotPresent:同InsertOrUpdate,不过存在对应的key时不再更新,返回值false为插入失败,true插入成功; stringprintf.h:字符串格式化输出、打印; StringPrintf:格式化输出字符串(内部通过调用StringAppendV实现); SStringPrintf:同StringPrintf,但是传入的参数dst会被清空; StringAppendV:格式化字符串,内部vsnprintf与va结合进行格式化,并采取基于堆和栈的方式实现长短字符串的格式化(栈最大大小kSpaceLength(1024字节)); StringAppendF:同StringAppendV,内部不会清空参数dst,会追加格式化后的字符串; StringPrintfVector:打印格式化vector<string>数据容器,内部调用StringPrintf进行格式化; kStringPrintfVectorMaxArgs:StringPrintfVector中vector容器的最大参数(最大32个,若v容器大小大于该值将调用LOG(FATAL)); string_printf_empty_block:保护StringPrintfVector打印,为空块; substitute.h:类似于stringprintf.h的字符串格式化,但是比stringprintf.h更加高效且使用方式上有所不同; SubstituteArg:格式化参数类,提供了多个支持基本数据类型的构造函数,此外提供提取转化后字符串data和字符串数据长度size接口,对于基本数据转换利用 strutil.h中提供的快速转换,如FastInt32ToBuffer、FloatToBuffer等; Substitute:提供了支持至多9个参数的格式化字符串,参数为SubstituteArg类型或可转化为SubstituteArg类型的;此外格式化使用“$”后跟一个数字, 该数字值为对应SubstituteArg参数,使用示例: string str; strings::SubstituteAndAppend(&str,"My name is $0 $1 and I am $2 years old.",first_name,last_name,age);事实上$后的数字可以一样; SubstituteAndAppend:同Substitute,但是会对格式化后的字符串数据对应参数output进行追加; zero_copy_stream.h:提供最小化数据流拷贝操作,主要提供ZeroCopyInputStream和ZeroCopyOutputStream抽象基类操作的接口,具体实现类位于 zero_copy_stream_impl.h和zero_copy_stream_impl_lite.h中; 此两个抽象基类操作接口如下(ZeroCopyOutputStream没有提供Skip接口): Next:获取数据流中的一块数据,参数data为指向的数据指针,size为获取的数据长度,返回值为false表示没有可读的数据或出现异常; BackUp:在调用Next后,可以回退内部数据指针索引位置,这样下一次调用Next时可以重新获取前一段数据;参数值不可大于早期Next得到的size长度; Skip:跳过部分数据流,返回false则表示已到数据流末尾或发生异常,为防止异常,可结合ByteCount和早期的Next确定是否会达到数据流末尾; ByteCount:获取当前数据流位置; zero_copy_stream_impl_lite.h:对zero_copy_stream.h中的抽象基类的实现,主要提供基于array、string的输入和输出流实现; ArrayInputStream:类array的输入流,继承于ZeroCopyInputStream; 数据成员: data_:指向uint8类型的array的数据指针; size_:array数据的有效长度; block_size_:每次调用获取Next获取的数据最大长度; position_:当前数据的索引位置; last_returned_size_:最后一次调用Next返回的数据长度; 构造函数:参数data为指向数据array的指针(该数据array应在ArrayInputStream生命周期内是有效的),size为数据长度,block_size为Next获取的最大长度; ArrayOutputStream:类array的输出流,继承于ZeroCopyInputStream,操作大体同ArrayInputStream; StringOutputStream:支持string类型的输出流,继承于ZeroCopyInputStream; kMinimumSize:最小的new size大小,在处理Next操作中,调整目标string大小为kMinimumSize或2 * old_size或capacity()大小; CopyingInputStream:拷贝输入流;仅提供Read、Skip操作接口; Read:读取流中指定数据;参数buffer指向流数据针对,size数据流大小,返回值为读取到的字节数,返回0为读取到数据流尾,返回-1表示异常; Skip:跳过指定长度的数据流;返回值为跳过的实际长度; CopyingOutputStream:拷贝输出流,仅提供Write操作接口; Write:从给定buffer中读取size字节的数据至输出流;返回值true表示成功,false表示写入异常; CopyingInputStreamAdaptor:拷贝输入流适配器(事实上内部并非为zero-copy),继承于ZeroCopyInputStream,其以CopyingInputStream作为输入流对象; 数据成员: copying_stream_:CopyingInputStream类型的流对象指针; owns_copying_stream_:是否是copying_stream_对象的拥有者,便以在释放的时候释放copying_stream_对象资源; failed_:是否出现操作异常; position_:当前数据流位置索引; buffer_:读取到的数据流对象缓冲区; buffer_size_:读取到的数据流对象缓冲区大小; buffer_used_:调用Next最近一次的大小; backup_bytes_:调用BackUp的回退字节数; 成员函数: 构造函数,参数copying_stream为CopyingInputStream类型的流对象指针,block_size为数据缓冲区大小以初始化 buffer_size_(若为<0则为默认大小kDefaultBlockSize(8192)); SetOwnsCopyingStream:设置是否为copying_stream_对象的拥有者; AllocateBufferIfNeeded:分配为buffer_size_大小的buffer_缓冲区; FreeBuffer:释放buffer_缓冲区资源; 此外Next、BackUp、Skip、ByteCount为ZeroCopyInputStream的接口实现; CopyingOutputStreamAdaptor:拷贝输出流适配器(事实上内部并非为zero-copy),继承于ZeroCopyInputStream,其以CopyingOutputStream作为输出流对象; 数据成员: copying_stream_:CopyingOutputStream类型的流对象指针; owns_copying_stream_:是否是copying_stream_对象的拥有者,便以在释放的时候释放copying_stream_对象资源; failed_:是否出现操作异常; position_:当前数据流位置索引; buffer_:读取到的数据流对象缓冲区; buffer_size_:读取到的数据流对象缓冲区大小; buffer_used_:调用Next最近一次的大小; 成员函数: 构造函数,参数copying_stream为CopyingOutputStream类型的流对象指针,block_size为数据缓冲区大小以初始化 buffer_size_(若为<0则为默认大小kDefaultBlockSize(8192)); SetOwnsCopyingStream:设置是否为copying_stream_对象的拥有者; Flush:调用底层刷新写入数据至输出流; AllocateBufferIfNeeded:分配为buffer_size_大小的buffer_缓冲区; FreeBuffer:释放buffer_缓冲区资源; WriteBuffer:写入当前buffer_used_大小的数据至输出缓冲区数据; zero_copy_stream_impl.h:对zero_copy_stream.h中的抽象基类的实现,主要实现File、stream、Concatenating、Limiting等几种流实现; FileInputStream:文件描述的读操作类,继承于ZeroCopyInputStream; 先介绍CopyingFileInputStream:文件输入流类,继承于CopyingInputStream,实现读取文件数据; 数据成员: file_:文件描述符或文件句柄; close_on_delete_:关闭时,是否释放、删除文件描述对象; is_closed_:是否已关闭; errno_:IO操作错误码; previous_seek_failed_:最近一次seek是否失败; 成员函数: 构造函数参数为文件描述符或文件句柄 Close:关闭文件描述符或文件句柄; SetCloseOnDelete:设置关闭操作时,自动释放、文件描述对象; GetErrno:获取IO操作错误码; 此外Read、Skip为CopyingInputStream类的实现接口,实现文件的读取和跳过指定字节数的操作; 数据成员: copying_input_:CopyingFileInputStream类型的输入流对象; impl_:CopyingInputStreamAdaptor类型的输入流对象适配器,作为流输入对象的实现类; 成员函数: 构造函数参数file_descriptor文件描述初始化copying_output_,其与block_size输入流块大小初始化impl_; Close:关闭文件描述并刷新缓冲区,内部调用copying_input_的Close函数; SetCloseOnDelete:设置关闭操作时,自动释放、文件描述对象,内部调用copying_input_的SetCloseOnDelete函数; GetErrno:获取IO操作错误码,内部调用copying_input_的GetErrno函数; 此外Next、BackUp、Skip、ByteCount均内部调用impl_相应接口实现; FileOutputStream:文件描述的写操作类,继承于ZeroCopyOutputStream,接口实现与FileInputStream相似; 增加了Flush接口以刷新输出流,无Skip接口; IstreamInputStream:用以对C++输入流操作,继承于ZeroCopyInputStream;同FileInputStream,只是操作构造函数为istream的对象; 其内部读输入,使用istream的read、gcount、fail、eof接口操作; OstreamOutputStream:用以对C++输出流操作,继承于ZeroCopyOutputStream,同FileOutputStream,只是操作构造函数为ostream的对象; 其内部写输出,使用ostream的write、good接口操作; ConcatenatingInputStream:处理多个ZeroCopyInputStream输入流的stream对象操作,继承于ZeroCopyInputStream; 构造函数streams为ZeroCopyInputStream类型的指针数组,count为数组大小; LimitingInputStream:处理受限字节的输入流,,继承于ZeroCopyInputStream; 构造函数input为ZeroCopyInputStream类型的指针对象,limit为字节上限; ConcatenatingInputStream与LimitingInputStream仅为其他stream对象的包装而已;

 

posted @ 2019-10-10 12:50  浩月星空  阅读(3227)  评论(0编辑  收藏  举报