简介
protocol buff是一种协议,是谷歌推出的一种序列化协议
Java序列化协议也是一种协议
两者的目的是,将对象序列化成字节数组,或者说是二进制数据
准备
protobuf的两个jar包、 protoc.exe(生成java的源代码,需要写protobuf的配置文件才能生成。)
protobuf配置文件
任意目录新建文件夹(任意名字)==》新建proto文件(任意名字,例如player.proto)后缀为proto
//包名
option java_package = "com.proto";
//java_outer_classname的作用是将Paler类和Resource类整合到一个大的类中,一个大的Moudle中,名叫PlayerModule
option java_outer_classname = "PlayerModule";
//message相当于java中的class
message PBPlayer{
//在protobuf中没有int和long当时有对应的类型,int32是int类型,int64是long类型
//required意思是这个字段类型必须设置,加入不设置就会报错
//后面的123是key值,这些key值在message中是不能重复的,这里的key相当于{name:xiaoming}中的name
required int64 playerId = 1;
required int32 age = 2;
required string name = 3;
//repeated的意思是list,重复int的list
repeated int32 skills = 4;
}
message PBResource{
//金币
required int64 gold = 1;
required int32 energy = 2;
}
生成java代码
将上面的player.proto放到protoc.exe的同级目录===》在这个目录中新建build.bat
build.bat
//如果是生成c代码就是--cpp_out
//=后面是将java文件生成到哪个目录
protoc ./player.protp --java_out=./
//断点启动方便观察错误
pasue
点击build.bat会自动生成一个文件加com.proto ===》PlayerModule.java
举个?
新建项目==》libs用来放jar包==》新建proto目录用来放proto文件==》把上面的两个jar拷贝过去 》proto文件拷贝到proto目录中》protoc.exe和build.bat拷贝到项目根目录
修改build.bat
protoc ./proto/*.protp --java_out=./src
pasue
在src下新建PB2Bytes.java
package com.java;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.Arrays;
public class JAVA2Bytes {
public static void main(String[] args) throws Exception {
byte[] bytes = toBytes();
toPlayer(bytes);
}
/**
* 序列化
* @throws IOException
*/
public static byte[] toBytes() throws IOException{
Player player = new Player(101, 20, "peter");
player.getSkills().add(1001);
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteArrayOutputStream);
//写入对象
objectOutputStream.writeObject(player);
//获取 字节数组
byte[] byteArray = byteArrayOutputStream.toByteArray();
System.out.println(Arrays.toString(byteArray));
return byteArray;
}
/**
* 反序列化
* @param bs
* @throws Exceptipackage com.proto;
import java.util.Arrays;
import com.proto.PlayerModule.PBPlayer;
import com.proto.PlayerModule.PBPlayer.Builder;
/**
- protobuf学习
- @author
*/
public class PB2Bytes {
public static void main(String[] args) throws Exception {
byte[] bytes = toBytes();
toPlayer(bytes);
}
/**
- 序列化
*/
public static byte[] toBytes(){
//获取一个PBPlayer的构造器
Builder builder = PlayerModule.PBPlayer.newBuilder();
//设置数据
//上面skill是list,本应该setSkill,可是这里是setSkill(index,value),不是我们平常的skill
//可以直接addSkill(1001)添加1001这个技能
//前面文件文加了required前缀的必须要在这里设置值,不然会报错如下
//Message missing required field
builder.setPlayerId(101).setAge(20).setName("peter").addSkills(1001);
//构造出对象
PBPlayer player = builder.build();
//序列化成字节数组
byte[] byteArray = player.toByteArray();
System.out.println(Arrays.toString(byteArray));
return byteArray;
}
/**
- 反序列化
- @param bs
- @throws Exception
*/
public static void toPlayer(byte[] bs) throws Exception{
PBPlayer player = PlayerModule.PBPlayer.parseFrom(bs);
System.out.println("playerId:" + player.getPlayerId());
System.out.println("age:" + player.getAge());
System.out.println("name:" + player.getName());
System.out.println("skills:" + (Arrays.toString(player.getSkillsList().toArray())));
}
}
输出
[8,101,16,20,16,5,112,101,116,101,114,32,-23,7]
101
20
peter
1001
java序列化和反序列化
Player.java
package com.java;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
/**
- 玩家对象
-
-
*
*/
public class Player implements Serializable{
/**
- */
private static final long serialVersionUID = -5248069984631225347L;
public Player(long playerId, int age, String name) {
this.playerId = playerId;
this.age = age;
this.name = name;
}
private long playerId;
private int age;
private String name;
private List<Integer> skills = new ArrayList<>();
public long getPlayerId() {
return playerId;
}
public void setPlayerId(long playerId) {
this.playerId = playerId;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public List<Integer> getSkills() {
return skills;
}
public void setSkills(List<Integer> skills) {
this.skills = skills;
}
}
JAVA2Bytes.java
package com.java;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.Arrays;
public class JAVA2Bytes {
public static void main(String[] args) throws Exception {
byte[] bytes = toBytes();
toPlayer(bytes);
}
/**
* 序列化
* @throws IOException
*/
public static byte[] toBytes() throws IOException{
Player player = new Player(101, 20, "peter");
player.getSkills().add(1001);
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteArrayOutputStream);
//写入对象
objectOutputStream.writeObject(player);
//获取 字节数组
//ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteArrayOutputStream);
//最终是写到byteArrayOutputStream中,所以通过byteArrayOutputStream获得。
byte[] byteArray = byteArrayOutputStream.toByteArray();
System.out.println(Arrays.toString(byteArray));
return byteArray;
}
/**
* 反序列化
* @param bs
* @throws Exception
*/
public static void toPlayer(byte[] bs) throws Exception{
ObjectInputStream inputStream = new ObjectInputStream(new ByteArrayInputStream(bs));
Player player = (Player)inputStream.readObject();
//打印
System.out.println("playerId:" + player.getPlayerId());
System.out.println("age:" + player.getAge());
System.out.println("name:" + player.getName());
System.out.println("skills:" + (Arrays.toString(player.getSkills().toArray())));
}
}
输出
[-84,-19,0,5,115,114,0,15,99,111,109,46,106,97,118,97,46,80,108........]
101
20
peter
1001
不同
java序列化出来的字节数组比proto buff的长很多,字节数组短的话能够减少很多的带宽。
为什么?
java中的字节数组包括这个类的类信息、这个类有哪个字段、协议头、每个类叫什么名称、每个类是什么类型的、最后的数值是多少等。
proto buff不许要有配置文件,java不需要只要双方都是java就行,所以proto buff其实是把类的名称、类型、字段等都写到了配置文件中,所以在序列化的时候集成了这些描述信息,所以字节很短。
proto buff分配空间是有伸缩性的,比如int 在内存中是 4 个字节,proto buff根据实际大小分配1-5个字节,从概率学的角度讲大部分可能都是一个或者两个字节