• Netty学习——Netty和Protobuf的整合(二)


    Netty学习——Netty和Protobuf的整合(二)


    这程序是有瑕疵的,解码器那里不通用,耦合性太强,有两个很明显的问题,但是要怎么解决呢?
    如:再加一个内部类型 Person2,之前的代码就不能用了。

    问题1:客户端和服务器端 分别 这里解码器都不能写死吧

    问题2:客户端和服务器端Handler里面的泛型,也都不能写死吧

     Stack Overflow , 善用搜索引擎解决此问题

    在Stack Overflow上面搜的结果
    https://stackoverflow.com/questions/38363160/netty-protobuf-websocket-how-to-convert-binarywebsocketframe-to-protobuf-type
    Google:netty如何集成Protobuf的解码器,点开了前几篇帖子看了看
    https://www.cnblogs.com/Binhua-Liu/p/5577622.html
    里面提供了两种解决方案,挺详细的

    方法一:自定义协议,官网提供的有基于Netty的自定义协议的方法
    方法二: 通过消息的定义方式去解决问题

    方法二详解如下:
    1.在外层,就定义一个消息。
    2.通过枚举,来决定你要传递的类型是什么

    syntax ="proto2";
    
    package com.dawa.protobuf;
    
    option optimize_for = SPEED;
    option java_package ="com.dawa.netty.sixthexample";
    option java_outer_classname = "MyDataInfo"; 
    
    message MyMessage{
        enum DataType{
            PersonType = 1;
            DogType = 2;
            CatType =3;
        }
    
        required DataType data_type = 1;
    
        oneof dataBody{
            Person person =2;
            Dog dog = 3;
            Cat cat = 4;
        }
    }
    
    
    message Person{
        optional string name = 1;
        optional int32 age = 2;
        optional string address = 3;
    }
    
    message Dog{
        optional string name = 1;
        optional int32 age = 2;
    }
    
    message Cat{
        optional string name = 1;
        optional string city = 2;
    }

    oneof 关键词
    1.共享内存
    2.只存在一个

     使用protoc 重新生成一下proto文件

    然后修改 客户端和服务端的初始化器的类,从以前单一的指定修改成 枚举类型的指定

     修改之后的服务器端  Handler和Initializer代码

    package com.dawa.netty.sixthexample;
    
    import io.netty.channel.ChannelHandlerContext;
    import io.netty.channel.SimpleChannelInboundHandler;
    
    /**
     * @Title: TestServerHandler
     * @Author: 大娃
     * @Date: 2019/12/3 10:09
     * @Description: handler本身是个泛型,这里的泛型就是取 要处理的类型
     */
    public class TestServerHandler extends SimpleChannelInboundHandler<MyDataInfo.MyMessage> {
    
        @Override
        protected void channelRead0(ChannelHandlerContext ctx, MyDataInfo.MyMessage msg) throws Exception {
            MyDataInfo.MyMessage.DataType dataType = msg.getDataType();
            if (dataType == MyDataInfo.MyMessage.DataType.PersonType) {
                MyDataInfo.Person person = msg.getPerson();
                System.out.println(person.getName());
                System.out.println(person.getAge());
                System.out.println(person.getAddress());
            } else if (dataType == MyDataInfo.MyMessage.DataType.DogType) {
                MyDataInfo.Dog dog = msg.getDog();
                System.out.println(dog.getAge());
                System.out.println(dog.getName());
            } else {
                MyDataInfo.Cat cat = msg.getCat();
                System.out.println(cat.getName());
                System.out.println(cat.getCity());
            }
        }
    }
    package com.dawa.netty.sixthexample;
    
    import io.netty.channel.ChannelInitializer;
    import io.netty.channel.ChannelPipeline;
    import io.netty.channel.socket.SocketChannel;
    import io.netty.handler.codec.protobuf.ProtobufDecoder;
    import io.netty.handler.codec.protobuf.ProtobufEncoder;
    import io.netty.handler.codec.protobuf.ProtobufVarint32FrameDecoder;
    import io.netty.handler.codec.protobuf.ProtobufVarint32LengthFieldPrepender;
    
    /**
     * @Title: TestServerInitializer
     * @Author: 大娃
     * @Date: 2019/12/3 10:05
     * @Description:
     */
    public class TestServerInitializer extends ChannelInitializer<SocketChannel> {
    
        @Override
        protected void initChannel(SocketChannel ch) throws Exception {
            ChannelPipeline pipeline = ch.pipeline();
            //这里和之前的不一样了,但也就是处理器的不一样
            //编解码处理器,protobuf提供的专门的编解码器.4个处理器
            pipeline.addLast(new ProtobufVarint32FrameDecoder());
            //Decoder是重点,解码器,将字节码转换成想要的数据类型
            //参数  messageLite,外层的要转换的类的实例
            pipeline.addLast(new ProtobufDecoder(MyDataInfo.MyMessage.getDefaultInstance()));
            pipeline.addLast(new ProtobufVarint32LengthFieldPrepender());
            pipeline.addLast(new ProtobufEncoder());
            pipeline.addLast(new TestServerHandler());
        }
    }

    修改之后的客户端  Handler和Initializer的代码

    package com.dawa.netty.sixthexample;
    
    import io.netty.channel.ChannelInitializer;
    import io.netty.channel.ChannelPipeline;
    import io.netty.channel.socket.SocketChannel;
    import io.netty.handler.codec.protobuf.ProtobufDecoder;
    import io.netty.handler.codec.protobuf.ProtobufEncoder;
    import io.netty.handler.codec.protobuf.ProtobufVarint32FrameDecoder;
    import io.netty.handler.codec.protobuf.ProtobufVarint32LengthFieldPrepender;
    
    /**
     * @Title: TestClientInitializer
     * @Author: 大娃
     * @Date: 2019/12/3 10:43
     * @Description:
     */
    public class TestClientInitializer extends ChannelInitializer<SocketChannel> {
        @Override
        protected void initChannel(SocketChannel ch) throws Exception {
            ChannelPipeline pipeline = ch.pipeline();
            //这里和之前的不一样了,但也就是处理器的不一样
            //编解码处理器,protobuf提供的专门的编解码器.4个处理器
            pipeline.addLast(new ProtobufVarint32FrameDecoder());
            //Decoder是重点,解码器,将字节码转换成想要的数据类型
            //参数  messageLite,外层的要转换的类的实例
            pipeline.addLast(new ProtobufDecoder(MyDataInfo.MyMessage.getDefaultInstance()));
            pipeline.addLast(new ProtobufVarint32LengthFieldPrepender());
            pipeline.addLast(new ProtobufEncoder());
            //自己的处理器
            pipeline.addLast(new TestClientHandler());
        }
    }
    package com.dawa.netty.sixthexample;
    
    import io.netty.channel.ChannelHandlerContext;
    import io.netty.channel.SimpleChannelInboundHandler;
    
    import java.util.Random;
    
    /**
     * @Title: TestClientHandler
     * @Author: 大娃
     * @Date: 2019/12/3 10:44
     * @Description:
     */
    public class TestClientHandler extends SimpleChannelInboundHandler<MyDataInfo.MyMessage> {
    
        @Override
        public void channelActive(ChannelHandlerContext ctx) throws Exception {
            //处于活动状态
            int randomInt = new Random().nextInt(3);
            MyDataInfo.MyMessage myMessage = null;
    
            if (0 == randomInt) {
                myMessage = MyDataInfo.MyMessage.newBuilder().
                        setDataType(MyDataInfo.MyMessage.DataType.PersonType).
                        setPerson(MyDataInfo.Person.newBuilder().
                                setName("大娃").
                                setAge(22).
                                setAddress("北京").build()).
                        build();
            } else if (1 == randomInt) {
                myMessage = MyDataInfo.MyMessage.newBuilder().
                        setDataType(MyDataInfo.MyMessage.DataType.DogType).
                        setDog(MyDataInfo.Dog.newBuilder().
                                setName("一只狗").
                                setAge(2).build()).
                        build();
            } else {
                myMessage = MyDataInfo.MyMessage.newBuilder().
                        setDataType(MyDataInfo.MyMessage.DataType.CatType).
                        setCat(MyDataInfo.Cat.newBuilder().
                                setName("一只猫").setCity("上海").build()).
                        build();
            }
            ctx.channel().writeAndFlush(myMessage);
        }
    
        @Override
        protected void channelRead0(ChannelHandlerContext ctx, MyDataInfo.MyMessage msg) throws Exception {
    
        }
    }

    先启动服务器端,再启动客户端,成功获取到客户端发送的消息到服务器端,效果图如下

     

     点了好多下才随机出来的大娃,哈哈

  • 相关阅读:
    JAVA 动态代理
    IDEA 配置阿里云Maven
    JAVA Spring5静态代理
    Spring5 常用注解
    react
    Angular
    微信小程序
    H5
    vue-ui
    jQuery
  • 原文地址:https://www.cnblogs.com/bigbaby/p/11981445.html
Copyright © 2020-2023  润新知