跨语言平台编程,使用SOAP的话,该方式是使用xml的方式传输,会大大增长网络的IO,并且xml的解析复杂,下降报文的解析性能。java
message LogonReqMessage{ required int64 actID=1; required string passwd=2; }
关键说明:python
message
是消息的关键字LogonReqMessage
是消息名字,至关于java的类名required
前缀表示该字段未必要字段,序列化先后必须赋值的字段。protobuf还存在两个相似的关键字optional
和repeated
主要用于表示数组字段。1
和2
表示不一样的字段在序列化先后的二进制中的布局位置。在本例中,passwd
字段编码后的数据必定位于actID
后,该值在同一个message中不能重复。对于protobuf而言,标签1到15的字段在编码的时候是能够获得优化的(标签值和类型信息只占一个byte,标签范围16到2047占两个byte),protobuf可支持的字段数量是$2^{29}-1$。所以,应该将repeated类型的字段标签未与1~15,节省编码后的字节数量。enum UserStatus{ OFFLINE=0; ONLINE=1; } message UserInfo{ required int64 actID=1; required string name=2; required UserStatus=3; }
关键说明:c++
enum
是枚举类型的关键字,等同于java里面的enum
UserStatus
为枚举的名字;
而不是逗号,
OFFLINE
和ONLINE
表示枚举值0
和1
表示枚举所对应的实际整型值,可为任意整型值,无需从0开始。enum UserStatus{ OFFLINE=0; ONLINE=1; } message UserInfo{ required int64 actID=1; required string name=2; required UserStatus=3; } message LogonRespMessage{ required LoginResult logonResult = 1; required UserInfo userInfo = 2; }
关键说明:编程
LogonRespMessage
消息定义中包含另一个消息类型做为其字段,如UserInfo userInfo
;.proto
文件中,那么怎么包含其余proto文件中的message呢?ProtoBuf提供关键字import
将其余proto文件的message引入到当前proto文件中。例如Import "myproject/CommonMessages.proto"
required
类型的字段。optional
类型的字段。repeated
表示的字段能够包含0个或多个数据,有别于java的数组,由于java数组中至少包含一个元素。optional
或者repeated
类型的。.proto Type | Notes | C++ Type | Java Type |
---|---|---|---|
double | double | double | |
float | float | float | |
int32 | "Uses variable-length encoding. Inefficient for encoding negative numbers ¨C if your field is likely to have negative values use sint32 instead." | int32 | int |
int64 | "Uses variable-length encoding. Inefficient for encoding negative numbers ¨C if your field is likely to have negative values use sint64 instead." | int64 | long |
uint32 | Uses variable-length encoding. | uint32 | int |
uint64 | Uses variable-length encoding. | uint64 | long |
sint32 | Uses variable-length encoding. Signed int value. These more efficiently encode negative numbers than regular int32s. | int32 | int |
sint64 | Uses variable-length encoding. Signed int value. These more efficiently encode negative numbers than regular int64s. | int64 | long |
fixed32 | Always four bytes. More efficient than uint32 if values are often greater than 228. | uint32 | int |
fixed64 | Always eight bytes. More efficient than uint64 if values are often greater than 256. | uint64 | long |
sfixed32 | Always four bytes. | int32 | int |
sfixed64 | Always eight bytes. | int64 | long |
bool | bool | boolean | |
string | A string must always contain UTF-8 encoded or 7-bit ASCII text. | string | String |
bytes | May contain any arbitrary sequence of bytes. | string | ByteString |
optional
或者repeated
限定符,不然没法保证新老程序在互传消息的时候消息的兼容性。required
字段,optional
和repeated
类型字段能够移除,可是他们以前使用的标签不能使用了。int32
,uint32
,int64
,uint64
和bool
等类型之间是兼容的,sint32
和sint64
是兼容的,stirng
和byte
是兼容的,fixed32
和sfixed32
是兼容的,fixed64
和sfixed64
是兼容的,若是想修改原有字段类型,为了保证兼容性,只能将其修改成原有类型兼容的类型,不然打破新老消息格式的兼容性。optional
和repeated
限定符是相互兼容的。能够在.proto
文件中定义包名,如:package abc.lypgone
,该包名生成c++时,替换成名字空间,而java为java的包名。数组
protobuf 在.proto
文件中定义一些经常使用的选项,这样protobuf能够帮助咱们生成更匹配的目标语言代码。网络
protobuf的内置选项分为三个等级:工具
经常使用的protobuf选项有:布局
java_package
是文件级的选项,指定让生成的java代码的包名为该选项的值;与此同时,输出的文件也自动输出到对应包目录下(上例的com/companyname/projectname
目录下),该选项对C++没有影响。java_outer_classname
是文件级别的选项,指定生成的java代码的外部类名称。若是没有指定,java代码的外部类名称为当前文件的文件名部分,同时将文件名转为驼峰格式,如my_project.proto
,那么该文件的外部类名为MyProject
,该选项对C++代码无影响。注意,因为一个java文件只能有一个外部类或者外部接口,因此
.proto
文件中的message
定义的消息均为外部类的内部类,这样才能将这些消息定义到一个文件中。c++没有此限制。性能
SPEED
:表示生成的代码运行效率高,可是由今生成的代码编译后会占用更多的空间。CODE_SIZE
: 和SPEED偏偏相反,代码运行效率较低
,可是由今生成的代码编译后会占用更少的空间,一般用于资源有限的平台,如Mobile。LITE_RUNTIME
: 生成的代码执行效率高,同时生成代码编译后的所占用的空间也是很是少。这是以牺牲Protocol Buffer提供的反射功能为代价的。所以咱们在C++中连接Protocol Buffer库时仅需连接libprotobuf-lite,而非libprotobuf。在Java中仅需包含protobuf-java-2.4.1-lite.jar,而非protobuf-java-2.4.1.jar对于
LITE_MESSAGE
选项而言,其生成的代码均将继承自MessageLite
,而非Message
。优化
[pack = true]
: 由于历史缘由,对于数值型的repeated字段,如int3二、int64等,在编码时并无获得很好的优化,然而在新近版本的Protocol Buffer中,可经过添加[pack=true]的字段选项,以通知Protocol Buffer在为该类型的消息对象编码时更加高效。如:repeated int32 samples = 4 [packed=true]
。注:该选项仅适用于2.3.0以上的Protocol Buffer
[default = default_value]
: optional类型的字段,若是在序列化时没有被设置,或者是老版本的消息中根本不存在该字段,那么在反序列化该类型的消息是,optional的字段将被赋予类型相关的缺省值,如bool被设置为false,int32被设置为0。Protocol Buffer也支持自定义的缺省值,如:optional int32 result_per_page = 3 [default = 10]。
protoc --proto_path=IMPORT_PATH --cpp_out=DST_DIR --java_out=DST_DIR --python_out=DST_DIR path/to/file.proto
这里将给出上述命令的参数解释。
protoc
为Protocol Buffer提供的命令行编译工具。--proto_path
等同于-I
选项,主要用于指定待编译的.proto消息定义文件所在的目录,该选项能够被同时指定多个。--cpp_out
选项表示生成C++代码,--java_out
表示生成Java代码,--python_out
则表示生成Python代码,其后的目录为生成后的代码所存放的目录。path/to/file.proto
表示待编译的消息定义文件。注:对于C++而言,经过Protocol Buffer编译工具,能够将每一个.proto文件生成出一对.h和.cc的C++代码文件。生成后的文件能够直接加载到应用程序所在的工程项目中。如:MyMessage.proto生成的文件为MyMessage.pb.h和MyMessage.pb.cc。