Protobuf3
相关连接:
Google-protobuf(需要翻墙):https://developers.google.com/protocol-buffers/
Protobuf on github:https://github.com/google/protobuf
Git上的资源:https://github.com/google/protobuf/releases
Proto3协议格式:https://developers.google.com/protocol-buffers/docs/proto3
前言:protobuf是什么?
Protocol Buffers是一个跨语言、跨平台的具有可扩展机制的序列化数据工具。也就是说,我在ubuntu下用python语言序列化一个对象,并使用http协议传输到使用java语言的android客户端,java使用对用的代码工具进行反序列化,也可以得到对应的对象。听起来好像跟json没有多大区别。。。其实区别挺多的。
Google说protobuf是smaller,faster,simpler,我们使用google规定的proto协议定义语言,之后使用proto的工具对代码进行“编译”,生成对应的各个平台的源代码,我们可以使用这些源代码进行工作。
Proto2与proto3:
Proto2和proto3有些区别,包括proto语言的规范,以及生成的代码,proto3更好用,更简便,所以我们直接存proto3开始。
下载需要的资源:
1:proto编译工具
2:你需要的语言的依赖包
这些在https://github.com/google/protobuf/releases都可以下载,windows平台的编译工具使用protoc-3.0.0-beta-2-win32.zip这个压缩包里的exe可执行文件,mac和ubuntu平台可使用源码进行编译安装,具体步骤见https://github.com/google/protobuf下面的README.md.
定义你的协议:
1.建立协议文件,例如test.proto
2.写入测试内容,//代表注释
//我沿袭了上家公司的定义规范(在此谢谢曹老师)
syntax = "proto3";
package com.proto.test;
//定义规范:
//message类 均首字母大写 大写!!!!
//test url : /test
message Request10000 { //定义一个类,名称是Request10000 用于客户端请求
Params params = 1;
message Params {
string name = 1; //一些测试内容
int64 timestamp = 2; //时间戳 毫秒
repeated string usernames = 3; //一些测试内容
}
}
message Response10000 { //定义一个类,名称是Response10000 用于响应客户端请求
Data data = 1;
message Data {
//返回的数据
string helloname = 1; //一些测试内容
string timestamp = 2; //时间戳 毫秒
repeated string helloUsername = 3; //一些测试内容
}
}
3.编译(免责声明:以上代码是从一个项目里拷出来并删减的,没有测试过)
Windows平台下,新建gen.bat文件,输入内容:
protoc -I=. --python_out=gen_python *.proto
protoc -I=. --java_out=gen_java *.proto
protoc -I=. --javanano_out=gen_javanano *.proto
protoc -I=. --objc_out=gen_objc *.proto
保存。并把gen.bat、test.proto、protc.exe(上面下载的编译工具)放到同一个目录下,并在该目录下新建对应的输出文件夹,gen_java、gen_javanano等,双击gen.bat就会自动编译,如果成功的话,这些输出文件夹里就应该有对应的生成的代码了。Tip:为了查看编译时可能由于协议定义语法不正确导致的错误,我一般在cmd命令行下,进入该目录,输入gen.bat回车 编译,如果报错,下面可以看到错误信息。
4.使用:
4.1:服务器使用。
以java后台为例,java后台一般应使用java_out对应的输出代码,也即gen_java目录下的文件,这个文件里面的封装方式:无法针对每个对象的每个字段进行更改,只能通过builder构造返回对象,能够保证客户端数据的完整性。Java客户端可以用javanano_out,可以针对每个字段操作,方便一些。
把gen_java中的包导入工程后,你会发现报了一对错,因为你有一些依赖包需要导入。首先是proto底层的一些文件,这些都可以在protobuf-3.0.0源码包中找到,还有一些,他们的.proto源码可以在protobuf-3.0.0-beta-1\src\google\protobuf目录下找到,手动编译一下,倒入工程即可使用。我当初从源码中找这些依赖文件找了好久= =。再有就是一些google的其他jar包:guava.jar,gson-parent.jar。为了方便使用,我把proto底层的一些依赖包打包成了jar文件。
后台使用代码示例:
@RequestMapping("/test")
public String test(HttpServletRequest request,
HttpServletResponse response){
System.out.println("start at action");
LazyStringList names = null;
String name = "";
long timestamp = 0;
LazyStringArrayList outNames = new LazyStringArrayList();
try {
Request10000 requ = Request10000.parseFrom(request.getInputStream());
names = (LazyStringList) requ.getParams().getUsernamesList();
System.out.println(requ.getParams().getName());
name = requ.getParams().getName();
timestamp = requ.getParams().getTimestamp();
System.out.println("success insert at action");
} catch (IOException e) {
e.printStackTrace();
Response10000.Builder builder = Response10000.newBuilder();
Response10000 resp = builder.build();
try {
response.getOutputStream().write(resp.toByteArray());
return "dassds";
} catch (IOException e1) {
e1.printStackTrace();
}
}
System.out.println("success at action");
//builder data
Response10000.Data.Builder builder3 = Response10000.Data.newBuilder();
builder3.setHelloname("hello" + name);
builder3.setTimestamp("send timestamp is " + timestamp);
if(names != null){
for(int i = 0; i < names.size() ; i++){
outNames.add("hello" + names.get(i));
}
}
builder3.addAllHelloUsername(outNames);
Response10000.Data data = builder3.build();
//builde response
Response10000 resp = Response10000.newBuilder()
.setData(data)
.build();
try {