Protobuf入门

全称:  Protocol Buffer

类似功能产品或框架: Apache Thrift, CORBA, Web Service

主要作用: 跨平台、跨语言交互、通信

核心:序列、反序列化

特点:小、快、简单


这东西由Google出品,08年的时候Google把它开源了,官方支持C++JAVAPython三种语言,但是由很多第三方的库来支持其他语言。RPC (Remote Procedure Call) 也由第三方插件。


这东西实现的功能说穿了其实很简单:
1. 你必须提供一个供交互双方使用的数据类型的接口文件; (.proto文件)
2. Protocol buffer 会帮你根据该文件生成某语言的Proto类
a. 该类是数据类型对于该语言的一个封装,如Java就是一个class,包含了各种属性可以set, get
b. 利用该类可以很方便的进行读写交互,如Java,就可以直接调xxx.build().writeTo(OutputStream stream) 写到二进制文件中去
3. 发送方用protocol buffer生成二进制,接收方用protocol buffer解析成其对应的数据模型,从而实现交互

看上去挺像XML的,不是么?REST?
1. 客户端将需要的数据,封装成XML的样子发送;
2. 服务器端接受XML, 解析后用JAXB转成Java对象,并覆上值交给后面对应方法处理

事实上二者本来就可以相互替换,因为他们提供的功能非常类似。但不同的是,protocol buffer更轻,而且中间介质是二进制,所以速度更快。

Java例子:

环境:win7 32bit


  1. 从官网下载protocol的编译器,如protoc-2.5.0-win32.zip
  2. 解开来后放到自建目录protobuffer/bin/目录下,并把该目录加到系统PATH中,这样可以直接在命令行使用protoc命令
  3. 生成一个Maven项目:

    mvn archetype:generate -DgroupId=com.edi.poc -DartifactId=protobuf-test -DarchetypeArtifactId=maven-archetype-quickstart -DinteractiveMode=false

  4. 加入protobufferdependency

    <dependency>

            <groupId>com.google.protobuf</groupId>

            <artifactId>protobuf-java</artifactId>

            <version>2.5.0</version>   

    </dependency>

     

  5. src下写一个.proto文件如下:

    package tutorial;

     

    option java_package = "com.example.tutorial";

    option java_outer_classname = "AddressBookProtos";

     

    message Person {

        required string name = 1;

        required int32 id = 2;

        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 AddressBook {

        repeated Person person = 1;

    }

     

  6. protoc 命令根据该proto文件生成Java类文件

    protoc -I=$SRC_DIR --java_out=$DST_DIR $SRC_DIR/addressbook.proto

    实际命令:

    protoc -I=. --java_out=main/java addressbook.proto

     

  7. 然后就可以看到main/java/com/example/tutorial下产生了AddressBookProtos.java文件
  8. 好了,现在创建一个工具类来写,一个工具类来读

    写类:

    package com.edi.poc;

     

    import java.io.BufferedReader;

    import java.io.FileInputStream;

    import java.io.FileNotFoundException;

    import java.io.FileOutputStream;

    import java.io.IOException;

    import java.io.InputStreamReader;

    import java.io.PrintStream;

     

    import com.example.tutorial.AddressBookProtos.AddressBook;

    import com.example.tutorial.AddressBookProtos.Person;

    import com.example.tutorial.AddressBookProtos.Person.PhoneType;

     

    public class AddPerson {

     

    // This function fills in a Person message based on user input.

    static Person PromptForAddress(BufferedReader stdin, PrintStream stdout) throws IOException {

    Person.Builder person = Person.newBuilder();

     

    stdout.print("Enter person ID: ");

    person.setId(Integer.valueOf(stdin.readLine()));

     

    stdout.print("Enter name: ");

    person.setName(stdin.readLine());

     

    stdout.print("Enter email address (blank for none): ");

    String email = stdin.readLine();

    if(email.length()>0)

    person.setEmail(email);

     

    while(true){

    stdout.print("Enter a phone number(or leave blank to finish): ");

    String number = stdin.readLine();

    if(number.length()==0) break;

    Person.PhoneNumber.Builder phoneNumber = Person.PhoneNumber.newBuilder();

    phoneNumber.setNumber(number);

     

    stdout.print("Is this a mobile, home, or work phone?");

    String type = stdin.readLine();

    switch(type)

    {

    case "home":

    case "HOME":

    phoneNumber.setType(PhoneType.HOME);

    break;

    case "mobile":

    case "MOBILE":

    phoneNumber.setType(PhoneType.MOBILE);

    break;

    case "work":

    case "WORK":

    phoneNumber.setType(PhoneType.WORK);

    break;

    default:

    stdout.println("Unknown phone type. Using default.");

    }

     

    person.addPhone(phoneNumber);

    }

     

     

    return person.build();

    }

     

    public static void main(String[] args) throws Exception {

    if(args.length!=1){

    System.err.println("Usage: AddPerson ADDRESS_BOOK_FILE");

    System.exit(-1);

    }

     

    AddressBook.Builder addressBook = AddressBook.newBuilder();

     

    try {

    addressBook.mergeFrom(new FileInputStream(args[0]));

    } catch (FileNotFoundException e) {

    System.out.println(args[0] + ": File not found. Create a new file.");

    } catch (IOException e) {

    e.printStackTrace();

    }

     

    addressBook.addPerson(PromptForAddress(new BufferedReader(new InputStreamReader(System.in)), System.out));

     

    FileOutputStream output = new FileOutputStream(args[0]);

    addressBook.build().writeTo(output);

    output.close();

    }

    }

    读类:

    package com.edi.poc;

     

    import java.io.FileInputStream;

    import java.io.FileNotFoundException;

    import java.io.IOException;

     

    import com.example.tutorial.AddressBookProtos.AddressBook;

    import com.example.tutorial.AddressBookProtos.Person;

     

    public class ListPeople {

     

    static void print(AddressBook addressBook){

    for(Person p: addressBook.getPersonList())

    {

    System.out.println("Person ID: " + p.getId());

    System.out.println("        Name: " + p.getName());

    if(p.hasEmail())

    System.out.println("        E-mail: " + p.getEmail());

     

    for(Person.PhoneNumber num:p.getPhoneList())

    {

    switch(num.getType())

    {

    case MOBILE:

    System.out.print("        Mobile phone #: ");

    break;

    case HOME:

    System.out.print("        Home phone #: ");

    break;

    case WORK:

    System.out.print("        Work phone #: ");

    break;

    default:

    }

    System.out.println(num.getNumber());

    }

    }

    }

     

    public static void main(String[] args) throws FileNotFoundException, IOException {

    if(args.length!=1){

    System.err.println("Usage: ListPeople ADDRESS_BOOK_FILE");

    System.exit(-1);

    }

     

    AddressBook addressBook = AddressBook.parseFrom(new FileInputStream(args[0]));

     

    print(addressBook);

    }

    }

     

  9. 自己执行AddPerson类,写入一个文件,然后ListPeople类可以将之前写的读出来。

这个例子是读写一个文件,实际应用中,可以把输出流放到socket,进行直接交互,或者REST ->  关键字@Produce("application/x-protobuf")

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值