Protocol buffers are Google’s language-neutral, platform-neutral, extensible mechanism for serializing structured data – think XML, but smaller, faster, and simpler. You define how you want your data to be structured once, then you can use special generated source code to easily write and read your structured data to and from a variety of data streams and using a variety of languages.
ProtoBuf是Google的语言中立、平台中立、可扩展机制的序列化结构化数据(类似于xml但是更小更快更简单)。你只需定义一次,然后可以使用特殊生成的源代码轻松地在各种数据流中读写结构化数据,并使用各种语言。
下载编译器
下载地址
定义消息类型
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70
// 定义语法版本 syntax = "proto2"; // 定义包 package tt.learn.protobuf; // 代码生成器的参数 默认SPEED // SPEED 快速生成, CODE_SIZE 代码大小, LITE_RUNTIME 使用lite版本 option optimize_for = SPEED; // 如果是导出java代码,指明导出的java包, 如果未设置默认使用package option java_package = "tt.learn.protobuf"; // 如果是导出java代码, 指明类的名称, 如果未设置默认是文件名称 option java_outer_classname = "DataInfo"; // 导入其他proto import "other.proto"; // 定义消息 message Student { // 必须赋值该字段 required string name = 1; // 选填字段 optional int32 age = 2; // 设置默认值 optional string address = 3 [default = "北京"]; // 使用其他message的内部message optional Book.Author like_author = 4; // 定义一个数组 repeated Book book = 5; // 定义枚举 enum Sex { MAN = 0; WONAN = 1; } optional Sex sex = 5 [default = MAN]; // A 和 B使用相同的内存,只有其中一个被赋值 oneof test_oneof{ string A = 6; int B = 7; } } message Book { // 定义范围 extensions 100 to 200; optional string name = 1; // 一次性message 字段名为ending optional group Ending = 2 { optional string text = 2; } // 定义内部消息 message Author{ optional string name = 1; } // 使用map repeated MapFieldEntry map_field = N; } // 定义map的结构 message MapFieldEntry { optional key_type key = 1; optional value_type value = 2; }
通过编译器生成代码
1 2
# --java_out 定义输出java根目录 $ protoc --java_out=src/main/java src/protobuf/ServerMsg.proto
demo
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
public class ProtoBufDemo { public static void main (String[] args) throws InvalidProtocolBufferException { DataInfo.Student student = DataInfo.Student .newBuilder() .setName("张三" ) .setAge(34 ) .setAddress("福建" ) .build(); byte [] student2ByteArray = student.toByteArray(); DataInfo.Student student2 = DataInfo.Student.parseFrom(student2ByteArray); System.out.println(student2); System.out.println(student2.getAddress()); } }
使用
Netty中使用
netty内部支持ProtoBuf的使用
引入jar包
1 2 3 4 5 6 7 8
dependencies { testCompile group: 'junit' , name: 'junit' , version: '4.12' compile( "io.netty:netty-all:4.1.10.Final" , "com.google.protobuf:protobuf-java:3.7.0" , "com.google.protobuf:protobuf-java-util:3.7.0" ) }
使用Protobuf的编解码Handler
1 2 3 4 5 6 7 8 9 10 11 12
public class MyClientInitializer extends ChannelInitializer <SocketChannel > { @Override protected void initChannel (SocketChannel ch) throws Exception { ch.pipeline() .addLast(new ProtobufVarint32FrameDecoder()) .addLast(new ProtobufDecoder(ServerMsg.Msg.getDefaultInstance())) .addLast(new ProtobufVarint32LengthFieldPrepender()) .addLast(new ProtobufEncoder()) .addLast(new MyClientHandler()); } }
如果有多个Message对象类型,可是Netty只解码1个对象类型
封装一个oneof的Message
1 2 3 4 5 6 7 8 9 10 11 12
message Msg{ enum Type { A = 1; B = 2; } // 定义解析的类型 required Type type = 1; oneof body { A a = 2; B b = 3; } }
自己实现解码器