1. 程式人生 > >Netty對Protocol Buffer多協議的支持(八)

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

center end pipe 使用 read 回來 .sh cli outer

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

三.運行

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

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