Netty对Protocol Buffer多协议的支持(八)
一.背景
在上篇博文中笔者已经用代码演示了如何在netty中使用Protocol Buffer,然而细心的用户可能会发现一个明显的不足之处就是,我们的Handler只能处理一种特定的类型,而我们的项目中又不可能只有一种类型,那么这个问题该怎么解决了?多的不说,笔者直接上代码。
二.代码实现
2.1 message的编写
syntax = "proto2"; package com.rsy.netty.protobuf; option java_package = "com.rsy.netty.protobuf"; option java_outer_classname = "DataInfo"; message Datas{ enum DataType { personType = 1; dogType = 2; } required DataType data_type = 1; oneof type_data{ Person person = 2; Dog dog = 3; } } message Person{ required int32 id = 1; optional string name = 2; enum Gender { male = 1; female = 2; } optional Gender gender = 3; } message Dog { required float height = 1; optional string color = 2; optional int64 age = 3; }
2.2 生成Java代码,在此不再赘述。
2.3 服务端启动代码
public class ServerTest { public static void main(String[] args) throws Exception { EventLoopGroup bossGroup = new NioEventLoopGroup(); EventLoopGroup workerGroup = new NioEventLoopGroup(); try{ ServerBootstrap serverBootstrap = new ServerBootstrap(); serverBootstrap.group(bossGroup, workerGroup).channel(NioServerSocketChannel.class) .handler(new LoggingHandler(LogLevel.INFO)) .childHandler(new ServerChannelInitilizer()); ChannelFuture channelFuture = serverBootstrap.bind(8989).sync(); channelFuture.channel().closeFuture().sync(); }finally{ bossGroup.shutdownGracefully(); workerGroup.shutdownGracefully(); } } }
2.4 服务端通道初始化代码
public class ServerChannelInitilizer extends ChannelInitializer<SocketChannel>{ @Override protected void initChannel(SocketChannel ch) throws Exception { ChannelPipeline pipeline = ch.pipeline(); pipeline.addLast("protobufVarint32FrameDecoder", new ProtobufVarint32FrameDecoder()); pipeline.addLast("protobufDecoder", new ProtobufDecoder(DataInfo.Datas.getDefaultInstance())); pipeline.addLast("protobufVarint32LengthFieldPrepender", new ProtobufVarint32LengthFieldPrepender()); pipeline.addLast("protobufEncoder", new ProtobufEncoder()); pipeline.addLast("serverHandler", new ServerHandler()); } }
2.5 服务端Handler代码
public class ServerHandler extends SimpleChannelInboundHandler<DataInfo.Datas>{ @Override protected void channelRead0(ChannelHandlerContext ctx, DataInfo.Datas msg) throws Exception { /** * 因为最先写过来的是Person */ DataInfo.Person p = msg.getPerson(); System.out.println(msg.getDataType().toString()); System.out.println(p.getId()); System.out.println(p.getGender().toString()); System.out.println(p.getName()); DataInfo.Datas data = DataInfo.Datas.newBuilder() .setDataType(DataType.dogType) .setDog( DataInfo.Dog.newBuilder() .setAge(23) .setColor("红色") .setHeight(3.5f) ).build(); ctx.writeAndFlush(data); } }
2.6 客户端启动代码
public class ClientTest { public static void main(String[] args) throws Exception { EventLoopGroup eventLoopGroup = new NioEventLoopGroup(); try{ Bootstrap bootstrap = new Bootstrap(); bootstrap.group(eventLoopGroup).channel(NioSocketChannel.class) .handler(new ClientChannelInitializer()); ChannelFuture channelFuture = bootstrap.connect("localhost", 8989).sync(); channelFuture.channel().closeFuture().sync(); }finally{ eventLoopGroup.shutdownGracefully(); } } }
2.7 客户端通道初始化代码
public class ClientChannelInitializer extends ChannelInitializer<SocketChannel>{ @Override protected void initChannel(SocketChannel ch) throws Exception { ChannelPipeline pipeline = ch.pipeline(); pipeline.addLast("protobufVarint32FrameDecoder", new ProtobufVarint32FrameDecoder()); pipeline.addLast("protobufDecoder", new ProtobufDecoder(DataInfo.Datas.getDefaultInstance())); pipeline.addLast("protobufVarint32LengthFieldPrepender", new ProtobufVarint32LengthFieldPrepender()); pipeline.addLast("protobufEncoder", new ProtobufEncoder()); pipeline.addLast("clientHandler", new ClientHandler()); } }
2.8 客户端Handler处理代码
public class ClientHandler extends SimpleChannelInboundHandler<DataInfo.Datas>{ @Override protected void channelRead0(ChannelHandlerContext ctx, DataInfo.Datas msg) throws Exception { /** * 服务端写回来的是dog */ DataInfo.Dog dog = msg.getDog(); System.out.println(msg.getDataType().toString()); System.out.println(dog.getAge()); System.out.println(dog.getColor()); System.out.println(dog.getHeight()); } @Override public void channelActive(ChannelHandlerContext ctx) throws Exception { DataInfo.Datas data = DataInfo.Datas.newBuilder() .setDataType(DataType.personType) .setPerson( DataInfo.Person.newBuilder() .setId(23) .setGender(Gender.female) .setName("zhangsan") ) .build(); ctx.writeAndFlush(data); } }
三.运行
运行服务端启动代码,再运行客户端启动代码。