基于Netty的RPC架构学习笔记(八):protocol buff学习使用

简介

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个字节,从概率学的角度讲大部分可能都是一个或者两个字节

转载于:https://www.cnblogs.com/LeesinDong/p/10835356.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值