目录
1、protobuf 环境搭建
2、protobuf 语法
2.1 注释规则
2.2 数据类型
2.3 默认值规则
2.4 protobuf 选项
2.5 protoc 生成java文件
3、idea 生成插件
3.1 GenProtobuf
3.2 protobuf
4、序列化和 反序列化
4.1 常规序列化和反序列化
4.2 通用的反序列化
5、protostuff
6、总结
最近准备启动写个gameserver的计划,所以开始准备,网络协议方面准备使用protobuf ,这也是现在最流行的,最多使用的,所以今天就写下protobuf,虽然在项目中也一直在使用,但是也只是惯性使然,今天就全面的复习下,避免在使用的时候卡壳。开始吧。
注:因为使用java的缘故,所以我就我的经验写下protobuf在java中的使用,因为其他的语言不是很熟,同时经验不多,但是大同小异。
1、protobuf 环境搭建
protobuf是由Google开发的一套对数据结构进行序列化的方法,可用做通信协议,数据存储格式,等等。其特点是不限语言、不限平台、扩展性强,就像XML一样。与XML相比,protobuf有以下特点:
1.1 protobuf 的版本
最新版本地址:Releases · protocolbuffers/protobuf · GitHub
Maven 依赖配置,直接放进去,不用想太多
<dependency>
<groupId>com.google.protobuf</groupId>
<artifactId>protobuf-java</artifactId>
<version>3.18.0</version>
</dependency>
1.2 proto编译器
将主页一直往下拉,可以看到protoc的各种系统版本,根据自己的操作系统选择,我的是64位的win10 ,所以选择了win64,下载后解压就好,等会使用
2、protobuf 语法
proto3 的语法文档 :https://developers.google.com/protocol-buffers/docs/proto3
syntax = "proto3";
message SearchRequest {
string query = 1;
int32 page_number = 2;
int32 result_per_page = 3;
}
2.1 注释规则
为你的.proto 添加注释,使用 C/C++风格的 // 或者 /* ... */ 语法.
/* SearchRequest represents a search query, with pagination options to
* indicate which results to include in the response. */
message SearchRequest {
string query = 1;
int32 page_number = 2; // Which page number do we want?
int32 result_per_page = 3; // Number of results to return per page.
}
2.2 数据类型
基本上也都是常规的数据类型
数值: int32,int64,float ,double ,s开头(可变的,也就是编码的时候更紧凑),u开头(也就是无符号的,只能是正值),fix(固定长度的,一般不怎么用)
布尔值:bool
字符串:string
枚举 : enum
列表:repeated
二进制:bytes
基本上常用的也就是这些简单的类型,没什么特殊的。
2.3 默认值规则
定义了数据类型的,在不传的时候的默认值的规则是什么,下面以Java 为主
-
string:默认值是”“
-
bool : 默认值 是false
-
数值类型:默认值是0,0.f或者0.D.
-
枚举:默认值是第一个枚举值,也就是0
-
message 复合类型:在Java中时null.
message SearchResponse { repeated Result results = 1; } message Result { string url = 1; string title = 2; repeated string snippets = 3; }
2.4 protobuf 选项
protobuf 提供了一些选项设置生成的proto文件
option java_package = "com.example.foo";
option java_outer_classname = "Ponycopter";
option java_multiple_files = true;
option optimize_for = CODE_SIZE;
option java_package = "com.example.foo";
生成的java文件所在的包名
option java_outer_classname = "Ponycopter";
生成的类的名字
option java_multiple_files = true;
如果是false 则整个proto文件生成在一个java文件中,true 则一个message 生成一个java文件,注:不写的时候默认是false
option optimize_for = CODE_SIZE;
可以设置为 SPEED
, CODE_SIZE
, LITE_RUNTIM
SPEED : 代码的序列和转换等速度优先
CODE_SIZE:优化生成的代码大小
LITE_RUNTIME:生成的代码需要更少的运行时,一般不选用此选项。
2.5 protoc 生成java文件
拷贝你下载的protoc.exe 到你的proto 文件的所在地址,在文件夹shfit + 右键 ,选择打开cmd 窗口 运行下面的
protoc --java_out=./ XX.proto
--java_out
就是生成的输出地址
xx.proto
就是你要编译的proto 文件
不信你试试
3、idea 生成插件
java中开发最常用的就是IDEA 了,因为idea 的强大插件体系是真的好用,protobuf 的开发在idea中也是很方便,这里推荐两个proto的插件,助你在开发的时候如虎添翼。
3.1 GenProtobuf
生成proto 每次都输入命令有点烦的,所以有人写了插件genprotobuf ,在idea中点点就可以了,
安装:很简单,File -> Settings->Plugins,然后点击install 就可以了,等安装完成后就可以了
配置:Tools -> Config GenProtobuf
生成java文件:选择需要生成的proto文件,然后选择 quick gen protobuf rules ,可以按上一步配置的规则生成java文件
3.2 protobuf
protobuf 插件是支持proto文件的语法,对关键字进行高亮
4、序列化和 反序列化
4.1 常规序列化和反序列化
常规的使用
SimpleMessage.Builder builder = SimpleMessage.newBuilder();
builder.setName("香菜");
builder.setId(1);
builder.setIsSimple(true);
byte[] result=builder.build().toByteArray();//序列化
SimpleMessage msg;
try {
msg = SimpleMessage.parseFrom(result);
System.out.println(msg);
} catch (InvalidProtocolBufferException e) {
e.printStackTrace();
}
4.2 通用的反序列化
使用parser 进行反序列化,保存每个消息的parser,可以在启动的时候对消息进行扫描,将消息id 对应的协议进行保存
import com.google.protobuf.Parser;
import com.xin.msg.login.SimpleMessage;
import java.util.HashMap;
import java.util.Map;
public class MsgMgr {
public static Map<Integer, Parser> msgMap = new HashMap<>();
static {
// msgId - parser
msgMap.put(1, SimpleMessage.parser());
}
}
在进行解析的时候根据消息Id获取对应的parser 转换为 对应的消息,统一转换
Parser parser = MsgMgr.msgMap.get(headId);
int canReadBytes = decode.readableBytes();
byte[] data = new byte[canReadBytes];
decode.readBytes(data);
Object o = parser.parseFrom(data);
5、protostuff
使用protobuf 需要写proto 文件,这个文件是为了和客户端同步,其实有点烦,再把它编译成目标语言,这样使用起来就很麻烦。但是现在有了protostuff之后,就不需要依赖.proto文件了,他可以直接对POJO进行序列化和反序列化,使用起来非常简单。
github 地址 :GitHub - protostuff/protostuff: Java serialization library, proto compiler, code generatorhttps://github.com/protostuff/protostuff
maven 依赖,加到你的pom.xml就可以了
<dependency>
<groupId>io.protostuff</groupId>
<artifactId>protostuff-core</artifactId>
<version>1.7.4</version>
</dependency>
<dependency>
<groupId>io.protostuff</groupId>
<artifactId>protostuff-runtime</artifactId>
<version>1.7.4</version>
</dependency>
实例;
public final class Foo
{
String name;
int id;
public Foo(String name, int id)
{
this.name = name;
this.id = id;
}
}
static void roundTrip()
{
Foo foo = new Foo("foo", 1);
// this is lazily created and cached by RuntimeSchema
// so its safe to call RuntimeSchema.getSchema(Foo.class) over and over
// The getSchema method is also thread-safe
Schema<Foo> schema = RuntimeSchema.getSchema(Foo.class);
// Re-use (manage) this buffer to avoid allocating on every serialization
LinkedBuffer buffer = LinkedBuffer.allocate(512);
// ser
final byte[] protostuff;
try
{
protostuff = ProtostuffIOUtil.toByteArray(foo, schema, buffer);
}
finally
{
buffer.clear();
}
// deser
Foo fooParsed = schema.newMessage();
ProtostuffIOUtil.mergeFrom(protostuff, fooParsed, schema);
}
protostuff 就不具体介绍了,官方地址也贴上了,同时我也没在项目中使用,原因就是proto 文件还要发给客户短使用,proto是和客户端进行协议沟通的桥梁,要不然就要客户端自己写proto文件了,容易造成协议不一致。
6、总结
protobuf 只是一个通信协议,虽然有很多细节,但是并不需要太过于深入,等你遇到问题的时候再查文档不晚,记住常用的数据类型,工作中不影响搬砖就可以了,加油,下一步用起来。
送书,送书,送书
随着网络技术的迅速发展,如何有效地提取并利用信息,以及如何有效地防止信息被爬取,已成为一个巨大的挑战。本书从零基础开始讲解,系统全面,案例丰富,注重实战,既适合Python程序员和爬虫爱好者阅读学习,也可以作为广大职业院校相关专业的教材或参考用书。础操作、图形处理基本操作、简单图形的绘制和对象的管理等内容
京东自营购买链接:
《Python爬虫与反爬虫开发从入门到精通》(刘延林)【摘要 书评 试读】- 京东图书
当当自营购买链接:
《Python爬虫与反爬虫开发从入门到精通》(刘延林)【简介_书评_在线阅读】 - 当当图书
大家点赞关注,三天后在留言的同学中抽取送一本书
注:如果中奖了没关注则放弃