Protobuf数据文件编写

syntax = "proto2";
package cn.shafish.protobuf;

option optimize_for = SPEED;
option java_package = "cn.shafish.netty.sixthexcample";
option java_outer_classname = "DataInfo";

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

文件编写必读一(这样写有何意义??)

这里定义的MyMessage,可以明显看出包含了Person、Dog、Cat这三个message消息数据。这样做的目的是什么呢,在Netty使用的时候,我们需要指定传递数据的类型,如之前Handler文件中使用的String、TextWebSocketFrame类型等。大家需要知道Message定义的数据不仅仅只有一个,而使用枚举这种方式把proto文件中定义的所有message对象都包含进去了,在netty数据传递的时候就只需传MyMessage类型的数据即可。

下面具体分析一下这种写法

首先,明确的是在MyMessage对象中需要包含文件的所有对象数据(如例子的:Person、Dog、Cat),不仅如此,MyMessage还需要定义每一次传递的都是哪个对象数据。注意!使用MyMessage不是传递所有的数据,客户端选择对象数据进行传输,比如选Person Dog Cat中的Person进行与后台的数据传递。综上,在MyMessage中就有了甄别对象的标识 -- DataType 和 对象的数据 -- dataBody。oneof基本就是单选的意思,而且后一次的操作会覆盖所有之前的操作,覆盖具体可以看。(后面的 =1、=2为tab num,用于编译器字节的操作,编写时就只需要定义完就ok了,剩下的交给编译器 -- protoc操作)

Netty服务端使用Protobuf的生成类

TestServerInit

在服务端init中需要重新定义netty关于protobuf的协议

//将字节数组转对象的,对象转字节数组的
pipeline.addLast(new ProtobufVarint32FrameDecoder());
pipeline.addLast(new ProtobufDecoder(DataInfo.MyMessage.getDefaultInstance()));
pipeline.addLast(new ProtobufVarint32LengthFieldPrepender());
pipeline.addLast(new ProtobufEncoder());

TestServerHandler

而在服务端响应客户端的请求,需要判断传递的数据对象,根据对象进行数据响应
此时在handler中传递的数据类型为DataInfo.MyMessage(DataInfo为类名),完整代码如下:

public class TestServerHandler extends SimpleChannelInboundHandler<DataInfo.MyMessage> {
    @Override
    protected void channelRead0(ChannelHandlerContext ctx, DataInfo.MyMessage msg) throws Exception {
        DataInfo.MyMessage.DataType dataType = msg.getDataType();

        //根据在DataInfo中定义的对象进行判断、处理
        if(dataType == DataInfo.MyMessage.DataType.PersonType) {
            DataInfo.Person person = msg.getPerson();
            System.out.println(person.getAddress());
            System.out.println(person.getAge());
            System.out.println(person.getName());
        } else if(dataType == DataInfo.MyMessage.DataType.DogType) {
            DataInfo.Dog dog = msg.getDog();
            System.out.println(dog.getAge());
            System.out.println(dog.getName());
        } else if(dataType == DataInfo.MyMessage.DataType.CatType) {
            DataInfo.Cat cat = msg.getCat();
            System.out.println(cat.getCity());
            System.out.println(cat.getName());
        }
    }
}

Netty客户端使用Protobuf的生成类

客户端代码init部分与服务端相同,只需要建立对象数据并与传递数据

TestClientHandler

    //如果连接处于活动状态,客户端会向服务端发起请求
    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
       int randomNum = new Random().nextInt(3);
       DataInfo.MyMessage myMessage = null;

       //当randomNum为0时传输Person对象数据,为1时传输Dog对象数据,为2时传输Cat对象数据
       if(randomNum == 0) {
            myMessage = DataInfo.MyMessage.newBuilder().
                    setDataType(DataInfo.MyMessage.DataType.PersonType).
                    setPerson(DataInfo.Person.newBuilder().setAddress("珠海").setAge(22).setName("shafish").build()).
                    build();
       }else if(randomNum == 1){
           myMessage = DataInfo.MyMessage.newBuilder().
                   setDataType(DataInfo.MyMessage.DataType.DogType).
                   setDog(DataInfo.Dog.newBuilder().setAge(22).setName("shafish hh").build()).
                   build();
       }else if(randomNum == 2) {
           myMessage = DataInfo.MyMessage.newBuilder().
                   setDataType(DataInfo.MyMessage.DataType.CatType).
                   setCat(DataInfo.Cat.newBuilder().setCity("深圳").setName("shafish hhh").build()).
                   build();
       }
        ctx.writeAndFlush(myMessage);
    }

https://github.com/fishhello/learn/tree/master/netty/netty-study/src/main/java/cn/shafish/netty/sixthexcample