Google Protobuf是一種輕便高效的結構化數據存儲格式,能夠用於結構化數據序列化。它很適合作數據存儲或 RPC 數據交換格式。可用於通信協議、數據存儲等領域的語言無關、平臺無關、可擴展的序列化結構數據格式。java
編譯安裝:git
下載Java版 https://github.com/google/protobuf/releasesgithub
tar -zxvf xxx.tar.gzbootstrap
./configure數組
makeide
make installoop
protoc --version測試
mvn installui
mvn packagegoogle
使用:
Google Protobuf支持複雜的POJO對象的編解碼,而這些代碼是自動生成的。
首先寫文件Person.proto ,定義程序中須要處理的結構化數據,在 protobuf 的中,結構化數據被稱爲 Message。
syntax="proto3"; package com.luangeng.netty.protobuf; message Person { string username=1; // int32 age=2; // string sex=3; // }
執行命令
protoc -I=. --java_out=. Person.proto
格式: protoc -I=$SRC_DIR --cpp_out=$DST_DIR $SRC_DIR/***.proto
即在當前目錄下生成了Java文件PersonOutClass.java, 將它引入到工程並須要添加POM依賴
<dependency> <groupId>com.google.protobuf</groupId> <artifactId>protobuf-java</artifactId> <version>3.5.0</version> </dependency>
--
而後作一個簡單的編解碼測試:
public class TestProtoBuf { //編碼爲byte數組 private static byte[] encoder(PersonOuterClass.Person p) { return p.toByteArray(); } //從byte數組解碼 private static PersonOuterClass.Person decoder(byte[] b) throws InvalidProtocolBufferException { return PersonOuterClass.Person.parseFrom(b); } //使用builder實例來設置屬性 private static PersonOuterClass.Person create(){ PersonOuterClass.Person.Builder builder = PersonOuterClass.Person.newBuilder(); builder.setAge(10); builder.setSex("man"); builder.setUsername("luangeng"); return builder.build(); } public static void main(String[] args) throws InvalidProtocolBufferException { PersonOuterClass.Person p = create(); Q.p("before----------\n" + p.toString()); PersonOuterClass.Person p2 = decoder(encoder(p)); Q.p("afetr-----------\n" + p2.toString()); } }
---
輸出結果:
before----------
username: "luangeng"
age: 10
sex: "man"
afetr-----------
username: "luangeng"
age: 10
sex: "man"
在Netty中使用Google Protobuf實例:
Server端:
public class EchoServer { public static void main(String[] args) { new EchoServer().bind(8080); } public void bind(int port) { EventLoopGroup bossGroup = new NioEventLoopGroup(); EventLoopGroup workerGroup = new NioEventLoopGroup(); try { ServerBootstrap bootstrap = new ServerBootstrap(); bootstrap.group(bossGroup, workerGroup) .channel(NioServerSocketChannel.class) .option(ChannelOption.SO_BACKLOG, 100) .childHandler(new ChannelInitializer<SocketChannel>() { @Override protected void initChannel(SocketChannel ch) throws Exception { ch.pipeline().addLast(new ProtobufVarint32FrameDecoder()); ch.pipeline().addLast(new ProtobufDecoder(PersonOuterClass.Person.getDefaultInstance())); ch.pipeline().addLast(new ProtobufVarint32LengthFieldPrepender()); ch.pipeline().addLast(new ProtobufEncoder()); ch.pipeline().addLast(new EchoServerHandler()); } }); ChannelFuture future = bootstrap.bind(port).sync(); System.out.println("server started"); future.channel().closeFuture().sync(); } catch (InterruptedException e) { e.printStackTrace(); } finally { System.out.println("server shuting down"); bossGroup.shutdownGracefully(); workerGroup.shutdownGracefully(); } } } public class EchoServerHandler extends ChannelInboundHandlerAdapter { int count = 0; @Override public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { PersonOuterClass.Person p = (PersonOuterClass.Person) msg; System.out.println("Server received " + count++ + " :\n" + p.toString()); ctx.writeAndFlush(msg); } @Override public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { cause.printStackTrace(); ctx.close(); } }
---
Client端:
public class EchoClient { public static void main(String[] args) { new EchoClient().connect("127.0.0.1", 8080); } public void connect(String host, int port) { EventLoopGroup group = new NioEventLoopGroup(); try { Bootstrap bootstrap = new Bootstrap(); bootstrap.group(group).channel(NioSocketChannel.class) .option(ChannelOption.TCP_NODELAY, true) .handler(new ChannelInitializer<SocketChannel>() { protected void initChannel(SocketChannel ch) throws Exception { ch.pipeline().addLast(new ProtobufVarint32FrameDecoder()); ch.pipeline().addLast(new ProtobufDecoder(PersonOuterClass.Person.getDefaultInstance())); ch.pipeline().addLast(new ProtobufVarint32LengthFieldPrepender()); ch.pipeline().addLast(new ProtobufEncoder()); ch.pipeline().addLast(new EchoClientHandler()); } }); ChannelFuture future = bootstrap.connect(host, port).sync(); System.out.println("client started"); future.channel().closeFuture().sync(); } catch (InterruptedException e) { e.printStackTrace(); } finally { System.out.println("client shuting down"); group.shutdownGracefully(); } } } public class EchoClientHandler extends ChannelInboundHandlerAdapter { private int count = 0; private static PersonOuterClass.Person create(int i) { PersonOuterClass.Person.Builder builder = PersonOuterClass.Person.newBuilder(); builder.setAge(i); builder.setSex("man"); builder.setUsername("luangeng" + i); return builder.build(); } @Override public void channelActive(ChannelHandlerContext ctx) throws Exception { for (int i = 0; i < 20; i++) { ctx.writeAndFlush(create(i)); } } //服務端返回應答信息後調用 @Override public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { PersonOuterClass.Person p = (PersonOuterClass.Person) msg; Q.p("Client get " + count++ + " :\n" + p.toString()); } @Override public void channelReadComplete(ChannelHandlerContext ctx) throws Exception { ctx.flush(); } @Override public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { cause.printStackTrace(); ctx.close(); } }
---
執行結果:
client started
Client get 0 :
username: "luangeng0"
sex: "man"
Client get 1 :
username: "luangeng1"
age: 1
sex: "man"
Client get 2 :
username: "luangeng2"
age: 2
sex: "man"
Client get 3 :
username: "luangeng3"
age: 3
sex: "man"
Client get 4 :
username: "luangeng4"
age: 4
sex: "man"
Client get 5 :
username: "luangeng5"
age: 5
sex: "man"
Client get 6 :
username: "luangeng6"
age: 6
sex: "man"
Client get 7 :
username: "luangeng7"
age: 7
sex: "man"
Client get 8 :
username: "luangeng8"
age: 8
sex: "man"
Client get 9 :
username: "luangeng9"
age: 9
sex: "man"
Client get 10 :
username: "luangeng10"
age: 10
sex: "man"
Client get 11 :
username: "luangeng11"
age: 11
sex: "man"
Client get 12 :
username: "luangeng12"
age: 12
sex: "man"
Client get 13 :
username: "luangeng13"
age: 13
sex: "man"
Client get 14 :
username: "luangeng14"
age: 14
sex: "man"
Client get 15 :
username: "luangeng15"
age: 15
sex: "man"
end