proto 文件中定义多个消息

x33g5p2x  于2022-06-06 转载在 其他  
字(6.0k)|赞(0)|评价(0)|浏览(246)

一 点睛

可以在 proto 中定义多个类,然后从中选择任意一个类,可以在 proto 中定义多个 message,然后再将多个 message 以枚举的形式供使用时选择。

二 实战

1 proto 文件

MyMessage.proto

syntax = "proto2" ;
package netty.protobuf.diff ;
option optimize_for = SPEED ;
option java_package = "netty.protobuf.diff" ;
option java_outer_classname = "MyMessage" ;

message MessageData
{
    enum MessageType {
        PersonType = 1 ;
        DogType = 2 ;
    }

    required MessageType Message_Type = 1 ;

    oneof messageContent {
        PersonData person = 2 ;
        DogData dog = 3 ;
    }
}

message PersonData {
    optional string pname = 1 ;
    optional int32 page = 2 ;
}
message DogData {
    optional string dname = 1 ;
    optional string dcolor = 2 ;
}

2 客户端

MyNettyClientTest

package netty.protobuf.diff;

import io.netty.bootstrap.Bootstrap;
import io.netty.channel.Channel;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioSocketChannel;

public class MyNettyClientTest {
    public static void main(String[] args) {
        EventLoopGroup eventLoopGroup = new NioEventLoopGroup();
        try {
            Bootstrap bootstrap = new Bootstrap();
            bootstrap.group(eventLoopGroup)
                    .channel(NioSocketChannel.class)
                    .handler(new MyNettyClientInitializer());
            Channel channel = bootstrap.connect("127.0.0.1", 8888).sync().channel();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            eventLoopGroup.shutdownGracefully();
        }
    }
}

MyNettyClientInitializer

package netty.protobuf.diff;

import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.socket.SocketChannel;
import io.netty.handler.codec.protobuf.ProtobufEncoder;
import io.netty.handler.codec.protobuf.ProtobufVarint32FrameDecoder;
import io.netty.handler.codec.protobuf.ProtobufVarint32LengthFieldPrepender;

public class MyNettyClientInitializer  extends ChannelInitializer<SocketChannel> {
    protected void initChannel(SocketChannel sc) throws Exception {
        ChannelPipeline pipeline = sc.pipeline();
        pipeline.addLast("ProtobufVarint32FrameDecoder",new ProtobufVarint32FrameDecoder()) ;
        pipeline.addLast("ProtobufVarint32LengthFieldPrepender",new ProtobufVarint32LengthFieldPrepender());
        // 用于将 MyMessage 类转为字节码
        pipeline.addLast("ProtobufEncoder",new ProtobufEncoder());
        // 构建 MyMessage 对象,并发送给服务端
        pipeline.addLast("MyNettyClientHandler", new MyNettyClientHandler());
    }
}

MyNettyClientHandler

package netty.protobuf.diff;

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

public class MyNettyClientHandler extends SimpleChannelInboundHandler<String> {
    @Override
    protected void channelRead0(ChannelHandlerContext ctx, String receiveMsg) {
    }

    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        // 如果 num=1,向服务端发送 person对象,否则发送 dog 对象
        int num = 1;
        MyMessage.MessageData message;
        MyMessage.MessageData.Builder messageBuilder = MyMessage.MessageData.newBuilder();
        MyMessage.PersonData.Builder personBuilder = MyMessage.PersonData.newBuilder();
        MyMessage.DogData.Builder dogBuilder = MyMessage.DogData.newBuilder();
        if (num == 1) {
            // 构建 person 对象
            MyMessage.PersonData person = personBuilder.setPname("zs").setPage(23).build();
            message = messageBuilder.setMessageType(MyMessage.MessageData.MessageType.PersonType).setPerson(person).build();
        } else {
            // 构建 dog 对象
            MyMessage.DogData dog = dogBuilder.setDname("wc").setDcolor("red").build();
            message = messageBuilder.setMessageType(MyMessage.MessageData.MessageType.DogType).setDog(dog).build();
        }
        ctx.channel().writeAndFlush(message);
    }
}

3 服务端

MyNettyServerTest

package netty.protobuf.diff;

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 MyNettyServerTest {
    public static void main(String[] args) {
        EventLoopGroup bossGroup = new NioEventLoopGroup();
        EventLoopGroup workerGroup = new NioEventLoopGroup();
        try {
            // ServerBootstrap:服务端启动时的初始化操作
            ServerBootstrap serverBootstrap = new ServerBootstrap();
            // 将bossGroup 和 workerGroup 注册到服务端的 Channel 上,并注册一个服务端的初始化器 NettyServerInitializer
            // 该初始化器中的 initChannel() 方法,会在连接被注册后立刻执行;最后将端口号绑定到 8888
            ChannelFuture channelFuture = serverBootstrap.group(bossGroup, workerGroup)
                    .channel(NioServerSocketChannel.class)
                    .childHandler(new MyNettyServerInitializer()).bind(8888).sync();
            channelFuture.channel().closeFuture().sync();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            bossGroup.shutdownGracefully();
            workerGroup.shutdownGracefully();
        }
    }
}

MyNettyServerInitializer

package netty.protobuf.diff;

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.ProtobufVarint32FrameDecoder;
import io.netty.handler.codec.protobuf.ProtobufVarint32LengthFieldPrepender;

public class MyNettyServerInitializer extends ChannelInitializer<SocketChannel> {
    protected void initChannel(SocketChannel sc) throws Exception {
        ChannelPipeline pipeline = sc.pipeline();
        pipeline.addLast("ProtobufVarint32FrameDecoder", new ProtobufVarint32FrameDecoder());
        // 用于将 byte[] 解码为 MessageData 对象
        pipeline.addLast("ProtobufDecoder", new ProtobufDecoder(MyMessage.MessageData.getDefaultInstance()));
        pipeline.addLast("ProtobufVarint32LengthFieldPrepender", new ProtobufVarint32LengthFieldPrepender());
        // MessageData
        pipeline.addLast("MyNettyServerHandler", new MyNettyServerHandler());
    }
}

MyNettyServerHandler

package netty.protobuf.diff;

import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
// 注意,此时 SimpleChannelInboundHandler 的泛型是 MessageData 类型
public class MyNettyServerHandler extends SimpleChannelInboundHandler<MyMessage.MessageData> {
    @Override
    protected void channelRead0(ChannelHandlerContext ctx, MyMessage.MessageData receiveMsg) throws Exception {
        MyMessage.MessageData.MessageType messageType = receiveMsg.getMessageType() ;
        // 判断
        if(messageType == MyMessage.MessageData.MessageType.PersonType){
            MyMessage.PersonData person = receiveMsg.getPerson() ;
            System.out.println(person.getPname()+"--" + person.getPage());
        }else{
            MyMessage.DogData dog = receiveMsg.getDog() ;
            System.out.println(dog.getDname()+"--" + dog.getDcolor());
        }
    }
}

三 测试

1 先启动服务端

2 再启动客户端

zs--23

相关文章