6.netty集成Protobuf序列化框架
来源:互联网 发布:软件测试工程师的出路 编辑:程序博客网 时间:2024/05/29 04:44
1.介绍
Protobuf是一个灵活高效、结构化的数据序列化框架,支持跨语言。
2.Protobuf开发环境
下载安装包windows下直接进入exe文件夹下面使用
创建proto文件:
person.proto:文件内容如下,这个文件用来配置我们需要序列化的对象以及属性。这个文件就是跨语言的关键option java_package = "com.tyf.netty"; option java_outer_classname="PersonProtos"; message person { required string name = 1; required int32 id = 2; }使用命令通过proto文件生成java工具类。当然使用其他语言的命令可以生成其他语言的工具类
生成了一个PersonProtos.java文件这个类是我们要序列化的person对象的一个工具类
接下来我们使用这java文件整合netty来使用
3.netty实现
刚刚生成的PersonProtos这个类中包含一个person内部类就是我们要持久化的类,还包含一些其他的方法用来build生成person对象然后序列化操作等
使用这个工具类需要的依赖
<!-- protobuf依赖 --><dependency> <groupId>com.google.protobuf</groupId> <artifactId>protobuf-java</artifactId> <version>3.4.0</version></dependency>
server:
设置proto编码解码器。直接打印msg可以看到对象信息
package com.tyf.netty;import io.netty.bootstrap.ServerBootstrap;import io.netty.channel.ChannelFuture;import io.netty.channel.ChannelHandlerAdapter;import io.netty.channel.ChannelHandlerContext;import io.netty.channel.ChannelInitializer;import io.netty.channel.ChannelOption;import io.netty.channel.ChannelHandler.Sharable;import io.netty.channel.EventLoopGroup;import io.netty.channel.nio.NioEventLoopGroup;import io.netty.channel.socket.SocketChannel;import io.netty.channel.socket.nio.NioServerSocketChannel;import io.netty.handler.codec.DelimiterBasedFrameDecoder;import io.netty.handler.codec.FixedLengthFrameDecoder;import io.netty.handler.codec.LengthFieldBasedFrameDecoder;import io.netty.handler.codec.LengthFieldPrepender;import io.netty.handler.codec.protobuf.ProtobufDecoder;import io.netty.handler.codec.protobuf.ProtobufEncoder;import io.netty.handler.codec.protobuf.ProtobufVarint32FrameDecoder;import io.netty.handler.codec.protobuf.ProtobufVarint32LengthFieldPrepender;import io.netty.handler.codec.string.StringDecoder;@Sharablepublic class MyServerHandler extends ChannelHandlerAdapter {@Overridepublic void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception{//直接将msg转换成person类PersonProtos.person obj = (PersonProtos.person)msg;//打印System.out.println("消息: "+obj.toString());}@Overridepublic void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {super.exceptionCaught(ctx, cause);}//创建起步程序public static void main(String [] argsStrings) throws Exception {//配置服务端NIO线程组(boss线程、worker线程)EventLoopGroup bGroup = new NioEventLoopGroup();EventLoopGroup wGroup = new NioEventLoopGroup();//创建启动辅助类ServerBootstrap bootstrap = new ServerBootstrap();bootstrap.group(bGroup, wGroup) .channel(NioServerSocketChannel.class) .option(ChannelOption.TCP_NODELAY, true) .option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 3000) .childHandler(new ChannelInitializer<SocketChannel>() {@Overrideprotected void initChannel(SocketChannel channel) throws Exception {//添加channel.pipeline().addLast("这个主要用来半包处理",new ProtobufVarint32FrameDecoder());channel.pipeline().addLast("使用刚刚生成的java类设置要序列化的具体类",new ProtobufDecoder(PersonProtos.person.getDefaultInstance()));channel.pipeline().addLast(new ProtobufVarint32LengthFieldPrepender());channel.pipeline().addLast(new ProtobufEncoder());channel.pipeline().addLast(new MyServerHandler());} });try {//监听本地端口,同步等待监听结果ChannelFuture future = bootstrap.bind(11111).sync();//等待服务端监听端口关闭,优雅退出future.channel().closeFuture().sync();}finally {bGroup.shutdownGracefully();wGroup.shutdownGracefully();} }}
client:
设置proto编解码器。使用PersonProtos工具类生成对象并序列化
package com.tyf.netty;import io.netty.bootstrap.Bootstrap;import io.netty.buffer.ByteBuf;import io.netty.buffer.Unpooled;import io.netty.channel.ChannelFuture;import io.netty.channel.ChannelHandlerAdapter;import io.netty.channel.ChannelHandlerContext;import io.netty.channel.ChannelInitializer;import io.netty.channel.ChannelOption;import io.netty.channel.EventLoopGroup;import io.netty.channel.nio.NioEventLoopGroup;import io.netty.channel.socket.SocketChannel;import io.netty.channel.socket.nio.NioSocketChannel;import io.netty.handler.codec.FixedLengthFrameDecoder;import io.netty.handler.codec.LengthFieldBasedFrameDecoder;import io.netty.handler.codec.LengthFieldPrepender;import io.netty.handler.codec.protobuf.ProtobufDecoder;import io.netty.handler.codec.protobuf.ProtobufEncoder;import io.netty.handler.codec.protobuf.ProtobufVarint32FrameDecoder;import io.netty.handler.codec.protobuf.ProtobufVarint32LengthFieldPrepender;import io.netty.handler.codec.string.StringDecoder;public class MyClientHandler extends ChannelHandlerAdapter {@Overridepublic void channelActive(ChannelHandlerContext ctx) throws Exception {//使用刚刚生成的java文件创建对象PersonProtos.person.Builder builder = PersonProtos.person.newBuilder();//使用build生成五个对象,写入缓冲builder.setName("name1");builder.setId(1);ctx.write(builder.build());builder.setName("name2");builder.setId(2);ctx.write(builder.build());builder.setName("name3");builder.setId(3);ctx.write(builder.build());//flushctx.flush();}@Overridepublic void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {super.exceptionCaught(ctx, cause);}//创建起步程序public static void main(String [] argsStrings) throws Exception {//配置客户端端NIO线程组EventLoopGroup bGroup = new NioEventLoopGroup();//创建客户端启动辅助类Bootstrap bootstrap = new Bootstrap();bootstrap.group(bGroup). channel(NioSocketChannel.class). option(ChannelOption.TCP_NODELAY, true). option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 3000). handler(new ChannelInitializer<SocketChannel>() {@Overrideprotected void initChannel(SocketChannel channel) throws Exception {//添加channel.pipeline().addLast("这个主要用来半包处理",new ProtobufVarint32FrameDecoder());channel.pipeline().addLast("使用刚刚生成的java类设置要序列化的具体类",new ProtobufDecoder(PersonProtos.person.getDefaultInstance()));channel.pipeline().addLast(new ProtobufVarint32LengthFieldPrepender());channel.pipeline().addLast(new ProtobufEncoder());channel.pipeline().addLast(new MyClientHandler());} });//发起异步连接ChannelFuture future = bootstrap.connect("127.0.0.1", 11111).sync();try {//等待客户端链路关闭future.channel().closeFuture().sync();} finally {//优雅退出,释放资源bGroup.shutdownGracefully();} }}
查看server端输出结果:这里不仅实现了对象序列化还提供了半包问题的解决
阅读全文