netty学习笔记8-protobuf多协议消息的支持

解决方案有2中:

第一种:官方列子中提到的自定义协议的方式,该方式比较繁琐且没有使用protobuf的任何特性

第二种:使用protobuf的one of 来定义共享空间的方式来解决protobuf不支持多协议的问题

本文使用使用第二种方式实现:

1. 编写.proto文件

syntax = "proto2";
package com.baidu.com.netty.protobuf;
option java_package = "com.baidu.com.netty.protobuf";
option java_outer_classname = "PersonData";
option optimize_for = SPEED;
message Person{
    required string name = 1;
    optional int32 age = 2;
    optional bool marraied = 3;
}
message Teacher{
    optional string name = 1;
    optional float pay = 2;
}
message Student{
    optional int64 id = 1;
    optional string name = 2;
}

message Message{
    enum DataType {
        PERSON = 1;
        TEACHER = 2;
        STUDENT = 3;
    }
    required DataType type = 1 [default = PERSON];
    oneof dataMsg {
        Person person = 2;
        Teacher teacher = 3;
        Student stu = 4;
    }
}

2. 使用protobuf的编译器生产对应的类

protoc --java_out= 生成的地址 proto文件存放的地址

3. 编写服务器端启动程序

package com.baidu.com.netty.protobuf;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;

public class MyServer {
    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).childHandler(new MyServerInitializer());
            ChannelFuture future = serverBootstrap.bind(8899).sync();
            future.channel().closeFuture().sync();
        }finally {
            bossGroup.shutdownGracefully();
            workerGroup.shutdownGracefully();
        }
    }
}

4. 编写服务器端初始化程序

package com.baidu.com.netty.protobuf;

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;

public class MyServerInitializer extends ChannelInitializer {
    @Override
    protected void initChannel(SocketChannel ch) throws Exception {
        ChannelPipeline pipeline = ch.pipeline();
        pipeline.addLast(new ProtobufVarint32FrameDecoder());
        pipeline.addLast(new ProtobufDecoder(PersonData.Message.getDefaultInstance()));
        pipeline.addLast(new ProtobufVarint32LengthFieldPrepender());
        pipeline.addLast(new ProtobufEncoder());
        pipeline.addLast(new MyServerHandler());
    }
}

5. 编写服务器端处理程序

package com.baidu.com.netty.protobuf;

import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;

public class MyServerHandler extends SimpleChannelInboundHandler {
    @Override
    protected void channelRead0(ChannelHandlerContext ctx, PersonData.Message msg) throws Exception {
        if(msg.getType() == PersonData.Message.DataType.PERSON)
        {
            PersonData.Person person = msg.getPerson();
            System.out.println(person.getName());
        } else if (msg.getType() == PersonData.Message.DataType.TEACHER)
        {
            PersonData.Teacher teacher = msg.getTeacher();
            System.out.println("我是一个老师,我叫: " + teacher.getName());
        } else if(msg.getType() == PersonData.Message.DataType.STUDENT)
        {
            PersonData.Student student = msg.getStu();
            System.out.println("我是一个学生,我叫: " + student.getName());
        }
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
       // cause.printStackTrace();
        ctx.close();
    }
}

6. 编写客户端启动程序和初始化程序

7. 编写客户端处理程序

package com.baidu.com.netty.protobuf;

import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.SimpleChannelInboundHandler;

import java.util.Random;

public class MyClientHandler extends SimpleChannelInboundHandler {
    @Override
    protected void channelRead0(ChannelHandlerContext ctx, PersonData.Message msg) throws Exception {
        if (null != msg && msg.getType().equals(PersonData.Message.DataType.PERSON))
        {
            PersonData.Person person = msg.getPerson();
            System.out.println(person.getName());
        }
    }

    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        int index = new Random().nextInt(3);
        System.out.println(index);
        PersonData.Message data = null;
        if(index == 0)
        {
            data = PersonData.Message.newBuilder().setType(PersonData.Message.DataType.PERSON).setPerson(PersonData.Person.newBuilder().setAge(10).setName("admin").build()).build();
        }else if (index == 1)
        {
            data = PersonData.Message.newBuilder().setType(PersonData.Message.DataType.TEACHER).setTeacher(PersonData.Teacher.newBuilder().setName("老徐").build()).build();
        }else if ((index == 2))
        {
            data = PersonData.Message.newBuilder().setType(PersonData.Message.DataType.STUDENT).setStu(PersonData.Student.newBuilder().setName("小学生").build()).build();
        }
        System.out.println(data);
        System.out.println(ctx);
        ctx.writeAndFlush(data);
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
       // cause.printStackTrace();
        ctx.close();
    }
}

你可能感兴趣的:(netty自学笔记)