golang使用protobuf

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

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

简介

和 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 设置语法类型,有 proto2 和 proto3 两种语法。
  2. package addressbook 可以设置生成的 golang 代码的包名。
  3. message 对应于 golang 中的 struct ,可以看到文件中一共定义了 Person , PhoneNumber , AddressBook 3个 message ,其中 PhoneNumber 是 Person 的嵌套类型。
  4. message 中有字段,可以是 int , string ,枚举或者其他消息类型。
  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.Marshal 和 proto.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

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

查看所有标签

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

How to Think About Algorithms

How to Think About Algorithms

Jeff Edmonds / Cambridge University Press / 2008-05-19 / USD 38.99

HOW TO THINK ABOUT ALGORITHMS There are many algorithm texts that provide lots of well-polished code and proofs of correctness. Instead, this one presents insights, notations, and analogies t......一起来看看 《How to Think About Algorithms》 这本书的介绍吧!

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

在线压缩/解压 CSS 代码

图片转BASE64编码
图片转BASE64编码

在线图片转Base64编码工具

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

Markdown 在线编辑器