@linux1s1s
2016-04-28T18:17:18.000000Z
字数 2995
阅读 2599
Java
2016-04
Protocol Buffers(简称protobuf)是谷歌的一项技术,用于将结构化的数据序列化、反序列化,经常用于网络传输。
这货实际上类似于XML生成和解析,但protobuf的效率高于XML,不过protobuf生成的是字节码,可读性比XML差。类似的还有json、Java的Serializable等。
详细了解可以参考Protocol Buffers,接下类将介绍一些基本的使用步骤。
首先通读Protocol Buffers,了解.proto
文件的基本格式和写法,下载官方给我们准备的工具,通过该工具可以将.proto
文件直接生成需要的代码源文件(比如Java/C/C++/Python等等),接下来直接将该源文件放到工程目录中,编写相应的序列化和反序列化等,这样就完成了整个流程,下面给出简单的实现步骤。
time.proto
option java_package = "com.test.app.pb.common";
option java_outer_classname = "TimeProto";
message Time {
optional int32 id = 1;
optional int32 startTime = 2;
optional int32 endTime = 3;
optional int64 systemTime = 4;
optional string countDownTip = 5;
optional int32 sEffectiveTime = 6;
optional int32 eEffectiveTime = 7;
optional string startTip = 8;
optional string endTip = 9;
}
上面的1、2、3、4是unique numbered tag,是一个唯一标识。这也是整个编码中的亮点,想一探究竟的可以继续往下看。
protoc工具使用的一般格式是:
protoc -I=$SRC_DIR --java_out=$DST_DIR $SRC_DIR/xxx.proto
protoc -I=$SRC_DIR --cpp_out=$DST_DIR $SRC_DIR/xxx.proto
其中SRC_DIR
是proto
文件所在的目录,DST_DIR
是编译proto
文件后生成的结构体处理文件的目录
之后会生成对结构体time.proto
中描述的各字段做序列化反序列化的类。
工具命令如下:
生成的java代码
将上面生成的代码加入到工程中去,再将Jar包导入工程中,或者添加如下Maver依赖
<dependency>
<groupId>com.google.protobuf</groupId>
<artifactId>protobuf-java</artifactId>
<version>2.6.1</version>
</dependency>
接下来写测试代码
TimeProto.Time.Builder timeBuilder = TimeProto.Time.newBuilder();
timeBuilder.setEEffectiveTime(20160428)
.setEndTime(20160429)
.setEndTip("End")
.setSEffectiveTime(20160428)
.setStartTime(20160426)
.setStartTip("Start")
.setSystemTime(20160428);
TimeProto.Time time = timeBuilder.build();
ByteArrayOutputStream output = new ByteArrayOutputStream();
try {
time.writeTo(output);
} catch (IOException e) {
e.printStackTrace();
}
try {
HttpClient httpClient = new DefaultHttpClient();
url = NetworkUtils.getCompleteUrl(url, getParams);
HttpGet request = new HttpGet(url);
HttpResponse response = httpClient.execute(request);
ByteArrayBuffer buffer = new ByteArrayBuffer(32 * 1024);
InputStream in = null;
try {
HttpEntity entity = response.getEntity();
if (entity == null) {
} else {
in = response.getEntity().getContent();
}
int temp;
byte[] bytes = new byte[8096];
while ((temp = in.read(bytes)) != -1) {
buffer.append(bytes, 0, temp);
}
} catch (SocketTimeoutException e) {
throw new HttpException(HttpException.MSG_NETWORK_ERROR, e);
} catch (IOException e) {
throw new HttpException(HttpException.MSG_NETWORK_ERROR, e);
} finally {
if (in != null) {
try {
in.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
byte[] result = buffer.toByteArray();
try {
TimeProto.Time timeResp = TimeProto.Time.parseFrom(result);
} catch (InvalidProtocolBufferException e) {
e.printStackTrace();
}
} catch (SocketTimeoutException e) {
throw new HttpException(HttpException.MSG_NETWORK_ERROR, e);
} catch (IllegalStateException e) {
throw new HttpException(HttpException.MSG_NETWORK_ERROR, e);
} catch (IOException e) {
throw new HttpException(HttpException.MSG_NETWORK_ERROR, e);
}
关键的逻辑在L33到L35行,拿到字符数组以后直接parse出来。
参考文档:
Protocol Buffers 官方文档
Java使用Protocol Buffers入门四步骤 如何使用
google protobuf源码分析1源码分析
Protocol Buffer技术详解(Java实例) 如何使用
玩转Protocol Buffers 如何使用
Google Protocol Buffer 的使用和原理 原理和使用
Why Protocol Buffer So Fast? ----protobuf编码详解 原理和使用
Protocol Buffers编码详解,例子,图解 原理和使用