正井猫

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理 ::

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);
    }
}

三.运行

  运行服务端启动代码,再运行客户端启动代码。

 

posted on 2017-06-18 22:44  正井猫  阅读(2594)  评论(0编辑  收藏  举报