这几天在写一个服务端的socket的通信服务器,以前是本身定义的协议由于,由于只是android客户端和服务器通信,后来iOS也链接到这个socket服务器上,为了跨语言通信,发现Google的 ProtoBuf(Protocol Buffer)支持跨语言通信,并且效率很是高。javascript
Google Protocol Buffer( 简称 Protobuf) 是 Google 公司内部的混合语言数据标准,后来才开源的,它是一个灵活、高效、结构化的序列化数据结构,它与传统的XML等通信相比,它的更小、更快、更简单。java
1.protoBuf在Google内部长期使用,产品稳定成熟,不少商业的项目都选择使用
2.跨语言,它支持Java、C++、Python、ObJect-c、C#、Go等语言,
3.protoBuf编码后消息更小、有利于存储传输
4.编码和解码的效率很是之高
5.支持不一样版本的协议向前兼容
6.支持自定义可选和必选字段
android
这里使用Java语言实现,咱们首选要定义一个protoBuf格式的通信协议,Login.proto文件git
package test;
option java_package = "sg.com.protobuf";
option java_outer_classname = "LoginProto";
message Login{
required int32 id = 1;
required string name = 2;
required string pws = 3;
optional string email = 4;
}复制代码
package:指定生成Java代码文件的包名
java_package:指定生Java类的包名
java_outer_classname:指定生成Java代码的外部类名称。若是没有指定该选项,Java代码的外部类名称为当前文件的文件名部分,同时还要将文件名转换为驼峰格式,如:my_project.proto
message:protoBuf消息定义的关键字,至关于Java中的class
required:数据类型的前缀,表示该字段为必要字段,既在序列化和反序列化以前该字段必须已经被赋值
repeated:表示这个字段的值能够容许被重复屡次,若是转换成JAVA代码,此filed数据结构为list,有序的。能够在“repeated”类型的filed后使用“packed”--压缩,提升数据传输的效率。
optional: 表示这个值是可选的容许为null
ProtoBuf类型和Java类型对应关系
github
完成消息的定义以后,就能够经过protoc.exe编译了
数组
LoginProto.Login.Builder builder = LoginProto.Login.newBuilder();
builder.setId(1);
builder.setName("sgtest");
builder.setPws("123");
builder.setEmail("test@163.com");
//获取login的实例
LoginProto.Login login = builder.build();
System.out.println(login);
//序列化
System.out.println("---------");
byte[] bytes = login.toByteArray();
System.out.println("leng:"+bytes.length);
login =LoginProto.Login.parseFrom(bytes);
System.out.println(login);复制代码
实例化一个对象是很是方便的,使用Google给咱们生成的静态方法就能够,经过toByteArray()方法来实现序列,parseFrom(bytes)方法来实现反序列化,你会看到protoBuf序列化后的字节长度很是小,这个还不算强大的,下面再来看一中序列化的方式:服务器
//第二种序列化
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
login.writeDelimitedTo(byteArrayOutputStream);
//反序列化
ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(byteArrayOutputStream.toByteArray());
login = LoginProto.Login.parseDelimitedFrom(byteArrayInputStream);
System.out.println(login.getEmail());复制代码
作过大量socket数据传输的同窗都知道,socket很容易发生粘包、拆包的问题,会致使数据解析错误,protoBuf能够搞定它,login.writeDelimitedTo(byteArrayOutputStream)方法,将一个对象序列化输出到一个字节数组流中,它在序列化的字节数组以前,添加一个varint32的数字表示字节数组的长度,因此实际放在字节数据中内容应该是数据的长度加上数据的内容,下面是该方法的源码
网络