protocol buf是伟大的google发布的一套开源编码规则,几乎涵盖了所有主流语言,它是基于二进制流的序列化传输,性能上要优于xml,json,thrift。
本篇将介绍它的安装与python环境下的使用,顺便啰嗦几句语法问题。
安装protocol buf篇:
一、下载源码
下载地址 :https://github.com/google/protobuf/archive/v3.0.0.zip
二、 解压,进入解压后的文件夹
三、 修改配置文件
你会看到一个名为autogen.sh的文件,运行./autogen.sh 本应该下载gmock,但是由于众所周知的原因,你无法从google提供的地址下载它,因此需要修改下载地址到一个可以下载的地方,找到文件的第34行,将其修改为:
curl $curlopts -L -o gmock-1.7.0.zip https://github.com/peter-wangxu/gMock/archive/1.7.0.zip
四、正式安装
$ ./configure $ make $ make check $ sudo make install $ sudo ldconfig # refresh shared library cache.更详细安装步骤,可参考这篇博客
安装python包
非常简单,pip install protobuf
编译.proto文件
1、touch addressbook.proto
2、输入内容
package kwsy;
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;
}
在当前文件夹下执行命令 protoc --python_out=. ./addressbook.proto
会生成一个名为 addressbook_pb2.py 这个,就是python在序列化与反序列化时要用到的模板
序列化与反序列化
序列化代码:
#coding=utf-8
import json
import addressbook_pb2
address_book = addressbook_pb2.AddressBook()
person = address_book.person.add()
person.id = 3
person.name = u'张东升'
email = 'xigongda200608@163.com'
phone_number = person.phone.add()
phone_number.number = '15801124142'
phone_number.type = addressbook_pb2.Person.MOBILE
person2 = address_book.person.add()
person2.id = 4
person2.name = 'dongsheng.zhang'
data = address_book.SerializeToString()
print len(data)
json_data = [
{'id':3,'name':u'张东升','email':'xigongda200608@163.com','phone':[
{'number':'15801124142','type':1}
]},
{
'id':4,
'name':'dongsheng.zhang'
}
]
json_data = json.dumps(json_data)
print len(json_data)
f = open('protocol.buf', "wb")
f.write(data)
f.close()
我这里同时使用json进行了序列化,两者相比,protocol 序列化后的字符串长度大约为json序列化后的三分之一
反序列化代码如下:
#coding=utf-8
import addressbook_pb2
address_book = addressbook_pb2.AddressBook()
f = open('protocol.buf', "rb")
address_book.ParseFromString(f.read())
f.close()
for person in address_book.person:
print person
for tel in person.phone:
print tel
语法简要介绍
如果你是工作多年的老鸟,相信,仅仅是看一眼addressbook.proto,你基本上就已经理解了它的语法
1、 package的作用是为了防止命名冲突的
2、message相当于class
3、required 的意思是必须有值,optional的意思是可选的,如果没有值就不赋值,default表示默认值
4、enum是枚举
5、repeated表示可重复,这就相当于数组嘛
6、message里可以嵌套message,这其实就是个内部类
7、最有意思的是每个字段定义的末尾都有一个标签,我没有仔细研究这个标签的作用,看样子,是为了标识序列化以后字段的位置用的,这个标签1-15这个范围内,最好给那些经常使用的字段,其原因在于,这样的字段在编码时,他的类型以及标签用一个字节来表示,超过这个标签范围的用两个字节,起初我搞不懂为什么,后来看了protocol的可定义类型就明白了,protocol可定义的字段类型有15个,标签的范围如果在1-15之间,那么他们自然可以放在一个字节里来表示,4个bit位表示字段类型,4个bit位表示标签。
更详细的语法介绍,请参考这篇博客