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

    三.运行

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

  • 相关阅读:
    Cypress安装使用(E2E测试框架)
    AirtestIDE详解(跨平台的UI自动化编辑器)
    Linux之自动化部署
    工作笔记 之 Python应用技术
    工作笔记 之 Linux服务搭建
    工作笔记 之 互联网实用技术
    Git全面应用
    Python-Thread(通俗易懂)
    php笔记(二)PHP类和对象之Static静态关键字
    php笔记(一)面向对象编程
  • 原文地址:https://www.cnblogs.com/miller-zou/p/7045711.html
Copyright © 2020-2023  润新知