最近在看fabric源码的时候看到了proto文件,以前没接触过,这次好好来看看.

网上说的很多的就都不详细说了,proto全称是protocol buffer,就是一种数据格式。是使用二进制进行的数据封装。 主要的结构是message,类似与go的struct(由于最近一直再用go,就全部用go进行对比)。然后也是支持这些基本的数据结构,像int32boolstring等等,在复杂的可以自己进行封装。 然后还可以进行import进行操作,具体的可以参看官网。 不过在使用的时候我遇到了一些问题。 #1.protoc的安转 由于我在使用go语言,在官网的release中并没有,很奇怪。只好自己去下载源码编译了。 首先是从官网下载zip文件。解压出来之后在根目录执行

1
2
3
4
5
./autogen.sh
./configure
make
make install
/sbin/ldconfig -v

(以上指令均在超级管理员身份下执行) 然后执行命令

1
protoc -h

出现帮助文档就好了。 然后安装针对Go的库

1
go get -u github.com/golang/protobuf/protoc-gen-go

执行结束 #2.proto的编写 proto提供了一系列数据结构,具体的可以在官网查阅. 我写了一个如下的结构

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
syntax="proto3";
package contact;
message Address{
    repeated string address=1;
}

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

message Contact{
    string phoneNum=1;
    PhoneType phoneType=2;
    Address address=3;
    string birthday=4;
    string occupy=5;
    string web=6;
}

就是一个联系人结构。使用以下指令

1
protoc --go_out=. contact.proto

就生成了针对这个文件的go文件--contact.pb.go。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
// Code generated by protoc-gen-go. DO NOT EDIT.
// source: contact.proto

/*
Package contact is a generated protocol buffer package.

It is generated from these files:
	contact.proto

It has these top-level messages:
	Address
	Contact
*/
package contact

import proto "github.com/golang/protobuf/proto"
import fmt "fmt"
import math "math"

// Reference imports to suppress errors if they are not otherwise used.
var _ = proto.Marshal
var _ = fmt.Errorf
var _ = math.Inf

// This is a compile-time assertion to ensure that this generated file
// is compatible with the proto package it is being compiled against.
// A compilation error at this line likely means your copy of the
// proto package needs to be updated.
const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package

type PhoneType int32

const (
	PhoneType_HOME   PhoneType = 0
	PhoneType_OFFICE PhoneType = 1
	PhoneType_MOBILE PhoneType = 2
)
..........

以下省略,做修改还是修改proto文件,而不是针对这个进行修改。 然后使用下试试看

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
package main

import (
	pb "contact"
	"fmt"
	"github.com/golang/protobuf/proto"
)

func main() {
	addr := &pb.Address{}
	addr.Address = append(addr.Address, "beijing")
	cont := &pb.Contact{}
	cont.PhoneNum = "12345"
	cont.PhoneType = pb.PhoneType_MOBILE
	cont.Address = addr
	cont.Birthday = "1995"
	fmt.Println(cont)
	data, err := proto.Marshal(cont)
	if err != nil {
		fmt.Println("marshal err")
	} else {
		fmt.Println(data)
	}
	cont1 := pb.Contact{}
	err = proto.Unmarshal(data, &cont1)
	if err != nil {
		fmt.Println("unmarshal err")
	} else {
		fmt.Println(cont1)
	}

}

很简单的内容。 显示的结果就暂时不贴了。 #proto的意义 如标题,我为什么要使用proto结构啊,而不是使用json,xml之类的呢? 做几个例子一探究竟。

1
2
3
4
5
6
7
8
phoneNum:"12345" phoneType:MOBILE address:<address:"beijing" > birthday:"1995" 
2017-11-08 14:48:43.43385463 +0800 CST
Marshal time:  35.041µs
[10 5 49 50 51 52 53 16 2 26 9 10 7 98 101 105 106 105 110 103 34 4 49 57 57 53]
data len: 26
2017-11-08 14:48:43.433901395 +0800 CST
Unmarshal time:  11.412µs
{12345 MOBILE address:"beijing"  1995  }

这个是运行输出结果。可以看出封装是µs级别,解封装一样。数据大小只有26. 同理,我改一改代码,生成JSON看一看。

1
2
3
4
5
6
7
8
phoneNum:"12345" phoneType:MOBILE address:<address:"beijing" > birthday:"1995" 
2017-11-08 14:51:12.712623597 +0800 CST
Marshal time:  81.038µs
[123 34 112 104 111 110 101 78 117 109 34 58 34 49 50 51 52 53 34 44 34 112 104 111 110 101 84 121 112 101 34 58 50 44 34 97 100 100 114 101 115 115 34 58 123 34 97 100 100 114 101 115 115 34 58 91 34 98 101 105 106 105 110 103 34 93 125 44 34 98 105 114 116 104 100 97 121 34 58 34 49 57 57 53 34 125]
data len: 86
2017-11-08 14:51:12.712729353 +0800 CST
Unmarshal time:  28.866µs
{12345 MOBILE address:"beijing"  1995  }

要封装的数据是一样的内容,但是数据大小达到了三倍多,序列化反序列化时间也都达到了两倍多。 再来试一试巨无霸xml

1
2
3
4
5
6
7
8
phoneNum:"12345" phoneType:MOBILE address:<address:"beijing" > birthday:"1995" 
2017-11-08 14:55:02.136333004 +0800 CST
Marshal time:  60.451µs
[60 67 111 110 116 97 99 116 62 60 80 104 111 110 101 78 117 109 62 49 50 51 52 53 60 47 80 104 111 110 101 78 117 109 62 60 80 104 111 110 101 84 121 112 101 62 50 60 47 80 104 111 110 101 84 121 112 101 62 60 65 100 100 114 101 115 115 62 60 65 100 100 114 101 115 115 62 98 101 105 106 105 110 103 60 47 65 100 100 114 101 115 115 62 60 47 65 100 100 114 101 115 115 62 60 66 105 114 116 104 100 97 121 62 49 57 57 53 60 47 66 105 114 116 104 100 97 121 62 60 79 99 99 117 112 121 62 60 47 79 99 99 117 112 121 62 60 87 101 98 62 60 47 87 101 98 62 60 47 67 111 110 116 97 99 116 62]
data len: 167
2017-11-08 14:55:02.136420589 +0800 CST
Unmarshal time:  74.649µs
{12345 MOBILE address:"beijing"  1995  }

令人比较吃惊地是解析时间跟封装时间差不多。 可以看到proto还是比较占据优势的,除了可读性很坑之外。在网络数据传输中会占据一席之地的。 #结语 也没有什么好说的了,proto这个是google大佬做的,还是比较好用的。