Netty對Protocol Buffer多協議的支持(八)


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

三.運行

  運行服務端啟動代碼,再運行客戶端啟動代碼。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM