Google - protoc学习(一)

一、简介

Google Protocol Buffer( 简称 Protobuf) 是 Google 公司内部的混合语言数据标准。他们用于 RPC 系统和持续数据存储系统。提供一个具有高效的协议数据交换格式工具库(类似Json)。
但相比于Json,Protobuf有更高的转化效率,时间效率和空间效率都是JSON的3-5倍。
可用于通讯协议、数据存储等领域的语言无关、平台无关、可扩展的序列化结构数据格式。目前提供了 C++、Java、Python 、OC、Swift等语言的 API。总只一句话就是很好,支持多平台且与语言无关。

二、小试牛刀

2.1、编写proto文件

首先我们需要编写一个 proto 文件,定义我们程序中需要处理的结构化数据,在 protobuf 的术语中,结构化数据被称为 Message。proto 文件非常类似 java 或者 C 语言的数据定义。

package lpk;                        
message helloworld 
{ 
   required int32     id = 1;  // ID 
   required string    name = 2;  // str 
   optional int32     age = 3;  //optional field
   repeated string    gender = 4 //至少被重复0次
}
message otherMassage{
        ....
}

解释下上文内容,package 名字叫做 lpk,定义了一个消息 helloworld,该消息有三个成员,类型为 int32 的 id,另一个为类型为 string 的成员 name。age 是一个可选的成员,即消息中可以不包含该成员。proto3的语法解释;再修饰符上和proto2存在差异。

标量:正如上述文件格式,在消息定义中,每个字段都有唯一的一个数字标识符。这些标识符是用来在消息的二进制格式中识别各个字段的,一旦开始使用就不能够再改变。注:[1,15]之内的标识号在编码的时候会占用一个字节。[16,2047]之内的标识号则占用2个字节。所以应该为那些频繁出现的消息元素保留 [1,15]之内的标识号。切记:要为将来有可能添加的、频繁出现的标识号预留一些标识号。

  • equired:一个格式良好的消息一定要含有1个这种字段。表示该值是必须要设置的;
  • optional:消息格式中该字段可以有0个或1个值(不超过1个)。
  • repeated:在一个格式良好的消息中,这种字段可以重复任意多次(包括0次)。重复的值的顺序会被保留。表示该值可以重复,相当于java中的List。

    2.2、编译protoc文件

    写好 proto 文件之后就可以用 Protobuf 编译器将该文件编译成目标语言了。我们暂且使用 C++。

    假设您的 proto 文件存放在 $SRC_DIR (你的protoc文件路径)下面,您也想把生成的文件放在同一个目录下,则可以使用如下命令:

    protoc -I=$SRC_DIR --cpp_out=$DST_DIR $SRC_DIR/你的protoc文件
    
    

    --cpp_out 输出c++文件命令;如果要生成oc文件:--objc_out 即可;
    命令将生成两个文件:

    lpk.helloworld.pb.h , 定义了 C++ 类的头文件

    lpk.helloworld.pb.cc , C++ 类的实现文件

    OC对应的文件:
    LpkHelloworld.pbobjc.h
    LpkHelloworld.pbobjc.m

    更多语言:http://code.google.com/intl/zh-CN/apis/protocolbuffers/docs/reference/overview.html

    2.3、使用protoc文件

    这里做简单的读写文件事例
    2.3.1写入本地文件
    
    #include "lpk.helloworld.pb.hpp"
    …
     
     int main(void) 
     { 
       
      lpk::helloworld msg1; 
      msg1.set_id(101); 
      msg1.set_name(“李平宽”); 
      msg1.set_age(18); 
         
      // Write the new address book back to disk. 
      fstream output("./log", ios::out | ios::trunc | ios::binary); 
             
      if (!msg1.SerializeToOstream(&output)) { 
          count << "失败" << endl; 
          return -1; 
      }         
      return 0; 
     }
    
    
    2.3.2 读取文件
    #include "lpk.helloworld.pb.hpp" 
    …
     void ListMsg(const lpk::helloworld & msg) { 
      cout << msg.id() << endl; 
      cout << msg.name() << endl; 
     } 
      
     int main(int argc, char* argv[]) { 
     
      lpk::helloworld msg1; 
      
      { 
        fstream input("./log", ios::in | ios::binary); 
        if (!msg1.ParseFromIstream(&input)) { 
          cerr << "读取失败" << endl; 
          return -1; 
        } 
      } 
      
      ListMsg(msg1); 
     }
    
    

    运行结果:

    101
    李平宽
    

    三、安装protoc

    3.1 检查是否安装过或安装成功

    打开终端输入 protoc --version ,如果提示有版本号则表示安装过;

    lipingkuandepingmu:~ linkface$ protoc --version
    libprotoc 3.6.1
    

    3.2、安装:mac环境配置

    下载地址: http://code.google.com/p/protobuf/downloads/list
    两种安装方式,不过首先得安装homebrew;
    首先检查电脑是否安装了homebrew,在终端输入 brew --version;

    linkface$ brew --version
    Homebrew 1.7.1
    Homebrew/homebrew-core (git revision 0ff2c; last commit 2018-08-02)
    

    说明已经安装过了;

    如果没有安装:

    /usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
    
    

    然后使用 下面这两个命令;

      brew install automake
      brew install libtool
    

    cd到你已经下载好的protoc的文件夹下;执行autogen.sh这个脚本;

    ./autogen.sh
    

    然后依次执行下面命令:

    ./configure 
    make check
    make
    make install
    

    检查是否安装成功

    protoc --version
    
    

    另外一种安装方式直接安装,

    brew protoc
    

    四、进阶

    4.1 嵌套message

    嵌套是一个神奇的概念,一旦拥有嵌套能力,消息的表达能力就会非常强大。

    message Person { 
     required string name = 1; 
     required int32 id = 2;        // Unique ID number for this person. 
     optional string email = 3; 
     
     enum PhoneType { 
       MOBILE = 0; 
       HOME = 1; 
       WORK = 2; 
     } 
     
     message PhoneNumber { 
       required string number = 1; 
       optional PhoneType type = 2 [default = HOME]; 
     } 
     repeated PhoneNumber phone = 4; 
    }
    

    在 Message Person 中,定义了嵌套消息 PhoneNumber,并用来定义 Person 消息中的 phone 域。这使得人们可以定义更加复杂的数据结构。

    4.2、import otherMessage

    在一个 .proto 文件中,还可以用 Import 关键字引入在其他 .proto 文件中定义的消息,这可以称做 Import Message,或者 Dependency Message。

    import common.header; 
     
    message youMsg{ 
     required common.info_header header = 1; 
     required string youPrivateData = 2; 
    }
    

    其中 ,common.info_header定义在common.header包内。

    Import Message 的用处主要在于提供了方便的代码管理机制,类似 C 语言中的头文件。您可以将一些公用的 Message 定义在一个 package 中,然后在别的 .proto 文件中引入该 package,进而使用其中的消息定义。

    Google Protocol Buffer 可以很好地支持嵌套 Message 和引入 Message,从而让定义复杂的数据结构的工作变得非常轻松愉快。

    五、其他

    5.1、和其他类似技术的比较

    看完这个简单的例子之后,希望您已经能理解 Protobuf 能做什么了,那么您可能会说,世上还有很多其他的类似技术啊,比如 XML,JSON,Thrift 等等。和他们相比,Protobuf 有什么不同呢?

    简单说来 Protobuf 的主要优点就是:简单,快。

    参考:

  • http://colobu.com/2015/01/07/Protobuf-language-guide/
  • https://www.cnblogs.com/jdonson/p/4763997.html

    六、介绍下OC的使用;

    主要区别是生成的OC文件。

    1、使用cocoapod 引入框架

    pod "ProtocolBuffers"
    pod  "Protobuf"
    

    这两个框架一个是协议,一个是路径配置文件;缺一不可;然后不需要任何和配置。

    2、 将上面生成的文件拖入工程中

        #import "LpkHelloworld.pbobjc.h"
    
    
        helloworld *lpk = [[helloworld alloc] init];
        lpk.id_p = 100000;
        lpk.age = 18;
        lpk.name = @"我是一坨牛粪";
        NSData *LpkData = [lpk data];
        NSLog(@"%@",LpkData);
        
        /// 反序列化
        NSError *error ;
        helloworld  *lpkStr = [helloworld parseFromData:LpkData error:&error];
        NSLog(@"%@",lpkStr);
        NSLog(@"name = %@,age = %d",lpkStr.name,lpkStr.age);
    

    打印结果

    2018-08-07 10:21:04.602563+0800 007[20329:2150888] <08a08d06 1212e688 91e698af e4b880e5 9da8e789 9be7b2aa 1812>
    2018-08-07 10:21:09.552132+0800 007[20329:2150888] : {
        id: 100000
        name: "我是一坨牛粪"
        age: 18
    }
    018-08-07 10:40:11.078623+0800 007[20616:2267973] name = 我是一坨牛粪,age = 18
    

    注意:这里特别提到id_p值必须给;否则data是null;

    3、总结

  • 使用cocoapod直接导入文件还是比较简单的不需要做任何配置。

  • 你可能感兴趣的:(Google - protoc学习(一))