golang使用protobuf

栏目: Go · 发布时间: 6年前

内容简介:和安装成功后,会在该

简介

http 中常用的 json 协议一样, protobuf 也是用来传输数据的,但是它使用二进制格式,传输效率更高。

安装

  1. 下载 protoc 二进制程序
    下载链接
    在windows上,选择protoc-3.7.0-rc-2-win64.zip 进行下载。
    压缩包中有两个文件夹:
    golang使用protobuf

    压缩包中文件夹.png

    bin 目录下的 protoc.exe 拷贝到 GOPATH/bin 目录下,将 include/ 目录下的 google 文件夹拷贝 GOPATH/src 目录下(只有使用protobuf的一些内置结构才需要用到该文件夹内的文件,这次并不会用到这个文件夹)。
  2. 安装 protobuf 的编译器插件 protoc-gen-go
    protoc 程序会调用 protoc-gen-go ,将 .proto 文件生成 golang 代码。可以使用 go get 命令安装:
go get -u -v github.com/golang/protobuf/protoc-gen-go

安装成功后,会在 GOPATH/bin 下生成 protoc-gen-go.exe 程序。

例子

demo 为官网 tutorial 的简化版本。

在GOPATH/src/all-demo下,目录结构为:

protobuf-demo
    demo1
        addressbook
            addressbook.pb.go
            addressbook.proto
        main.go

编写、编译addressbook.proto文件

其中 addressbook.proto 文件为:

// [START declaration]
syntax = "proto3";
package addressbook;

// [END declaration]

// [START messages]
message Person {
  string name = 1;
  int32 id = 2;  // Unique ID number for this person.
  string email = 3;

  enum PhoneType {
    MOBILE = 0;
    HOME = 1;
    WORK = 2;
  }

  message PhoneNumber {
    string number = 1;
    PhoneType type = 2;
  }

  repeated PhoneNumber phones = 4;
}

// Our address book file is just one of these.
message AddressBook {
  repeated Person people = 1;
}
// [END messages]

其中:

  1. syntax 设置语法类型,有 proto2proto3 两种语法。
  2. package addressbook 可以设置生成的 golang 代码的包名。
  3. message 对应于 golang 中的 struct ,可以看到文件中一共定义了 PersonPhoneNumberAddressBook 3个 message ,其中 PhoneNumberPerson 的嵌套类型。
  4. message 中有字段,可以是 intstring ,枚举或者其他消息类型。
  5. repeated 表示该字段可以不止一个,类似于 golang 中的 slice

编译

命令行进入 GOPATH/src/all-demo/protobuf-demo/demo1/addressbook ,

执行 protoc --go_out=. addressbook.proto ,会在该目录下生成 addressbook.pb.go 文件。

其中 --go_out 指定生成的 golang 文件的目录。

addressbook.pb.go 部分源码如下:

// 可以看到包名为addressbook
package addressbook
// [START messages]
type Person struct {
    Name                 string                `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
    Id                   int32                 `protobuf:"varint,2,opt,name=id,proto3" json:"id,omitempty"`
    Email                string                `protobuf:"bytes,3,opt,name=email,proto3" json:"email,omitempty"`
    Phones               []*Person_PhoneNumber `protobuf:"bytes,4,rep,name=phones,proto3" json:"phones,omitempty"`
    XXX_NoUnkeyedLiteral struct{}              `json:"-"`
    XXX_unrecognized     []byte                `json:"-"`
    XXX_sizecache        int32                 `json:"-"`
}
type Person_PhoneNumber struct {
    Number               string           `protobuf:"bytes,1,opt,name=number,proto3" json:"number,omitempty"`
    Type                 Person_PhoneType `protobuf:"varint,2,opt,name=type,proto3,enum=addressbook.Person_PhoneType" json:"type,omitempty"`
    XXX_NoUnkeyedLiteral struct{}         `json:"-"`
    XXX_unrecognized     []byte           `json:"-"`
    XXX_sizecache        int32            `json:"-"`
}
// Our address book file is just one of these.
type AddressBook struct {
    People               []*Person `protobuf:"bytes,1,rep,name=people,proto3" json:"people,omitempty"`
    XXX_NoUnkeyedLiteral struct{}  `json:"-"`
    XXX_unrecognized     []byte    `json:"-"`
    XXX_sizecache        int32     `json:"-"`
}

编写main.go

代码主要测试 proto.Marshalproto.UnMarshal 的功能。先定义一个 pb.AddressBook 结构体,并将其初始化,用 proto.Marshal 将其序列化成二进制数据,写入文件,再将其从文件中读取,使用 proto.UnMarshal 反序列化成结构体。

代码如下:

package main

import (
    "fmt"
    pb "all-demo/protobuf-demo/demo1/addressbook"
    "io/ioutil"
    "log"
    "github.com/golang/protobuf/proto"
)

func main() {
    // 自定义AddressBook内容
    book := &pb.AddressBook{
        People: []*pb.Person {
            &pb.Person{
                Id: 1,
                Name: "zyq",
                Email: "77@qq.com",
                Phones: []*pb.Person_PhoneNumber{
                    &pb.Person_PhoneNumber {
                        Number: "11111",
                        Type: pb.Person_MOBILE,
                    },
                    &pb.Person_PhoneNumber {
                        Number: "22222",
                        Type: pb.Person_HOME,
                    },
                },
            },
        },
    }
    fmt.Println("book : ",book)

    fname := "address.dat"
    // 将book进行序列化
    out, err := proto.Marshal(book)
    if err != nil {
        log.Fatalln("Failed to encode address book:", err)
    }
    // 将序列化的内容写入文件
    if err := ioutil.WriteFile(fname, out, 0644); err != nil {
        log.Fatalln("Failed to write address book:", err)
    }

    // 读取写入的二进制数据
    in, err := ioutil.ReadFile(fname)
    if err != nil {
        log.Fatalln("Error reading file:", err)
    }

    // 定义一个空的结构体
    book2 := &pb.AddressBook{}
    // 将从文件中读取的二进制进行反序列化
    if err := proto.Unmarshal(in, book2); err != nil {
        log.Fatalln("Failed to parse address book:", err)
    }

    fmt.Println("book2: ",book2)
}

执行结果为:

book :  people:<name:"zyq" id:1 email:"77@qq.com" phones:<number:"11111" > phones:<number:"22222" type:HOME > > 
book2:  people:<name:"zyq" id:1 email:"77@qq.com" phones:<number:"11111" > phones:<number:"22222" type:HOME > >

问题:

  • 还有很多语法不了解。
  • proto.UnMarshal 函数的声明为 func Unmarshal(buf []byte, pb Message) error ,该函数的第二个参数为 proto.Message 接口,在网络传输中,服务端怎么知道客户端发过来的到底是哪一种 message

参考

  1. https://developers.google.com/protocol-buffers/docs/gotutorial

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

编程之美:微软技术面试心得

编程之美:微软技术面试心得

《编程之美》小组 / 电子工业出版社 / 2018-9 / 79

《编程之美:微软技术面试心得》收集了约60道算法和程序设计的题目,这些题目大部分在微软的笔试、面试中出现过,有的曾被微软员工热烈地讨论过。作者试图从书中各种有趣的问题出发,引导读者发现问题、分析问题、解决问题,寻找更优的解法。《编程之美:微软技术面试心得》内容分为以下几个部分。 游戏之乐:从游戏和其他有趣问题出发,化繁为简,分析总结。 数字之魅:编程的过程实际上就是和数字及字符打交道的......一起来看看 《编程之美:微软技术面试心得》 这本书的介绍吧!

HTML 压缩/解压工具
HTML 压缩/解压工具

在线压缩/解压 HTML 代码

CSS 压缩/解压工具
CSS 压缩/解压工具

在线压缩/解压 CSS 代码

Markdown 在线编辑器
Markdown 在线编辑器

Markdown 在线编辑器