proto 文件中定义多个消息

一 点睛

可以在 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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
* 0 译者序 * 1 MySQL的一般的信息 o 1.1 什么是MySQL? o 1.2 关于本手册 + 1.2.1 本手册使用的约定 o 1.3 MySQL的历史 o 1.4 MySQL的主要特征 o 1.5 MySQL稳定性? o 1.6 顺应2000年 o 1.7 SQL一般信息和教程 o 1.8 有用的MySQL相关链接 * 2 MySQL 邮件列表及如何提问或报告错误 o 2.1 MySQL邮件列表 o 2.2 提问或报告错误 o 2.3 怎样报告错误或问题 o 2.4 在邮件列表上回答问题的指南 * 3 MySQL的许可证和技术支持 o 3.1 MySQL的许可证政策 o 3.2 MySQL 使用的版权 + 3.2.1 可能的未来版权改变 o 3.3 MySQL商业性分发 o 3.4 许可证实例 + 3.4.1 销售使用 MySQL的产品 + 3.4.2 销售MySQL相关的服务 + 3.4.3 ISP MySQL服务 + 3.4.4 运营一个使用MySQL的Web服务器 o 3.5 MySQL的许可证和技术支持费用 + 3.5.1 付款信息 + 3.5.2 联系信息 o 3.6 商业性支持的类型 + 3.6.1 基本的电子邮件支持 + 3.6.2 扩展的电子邮件支持 + 3.6.3 登录支持 + 3.6.4 扩展的登录支持 * 4 安装 MySQL o 4.1 怎样获得MySQL o 4.2 MySQL支持的操作系统 o 4.3 使用MySQL哪个版本 o 4.4 怎样和何时发布更新版本 o 4.5 安装布局 o 4.6 安装MySQL二进制代码分发 + 4.6.1 Linux RPM注意事项 + 4.6.2 构造客户程序 + 4.6.3 系统特定的问题 # 4.6.3.1 Linux 注意事项 # 4.6.3.2 HP-UX 注意事项 o 4.7 安装 MySQL源代码分发 + 4.7.1 快速安装概述 + 4.7.2 运用补丁 + 4.7.3 典型的configure选项 o 4.8 编译问题? o 4.9 MIT-pthreads 注意事项 o 4.10 Perl 安装说明 + 4.10.1 在Unix操作系统上安装 Perl + 4.10.2 在 Win32上安装 ActiveState Perl + 4.10.3 在 Win32 上安装 MySQL Perl 分发 + 4.10.4 使用 Perl DBI/DBD接口遇到的问题 o 4.11 系统特定的问题 + 4.11.1 Solaris注意事项 + 4.11.2 Solaris 2.7 注意事项 + 4.11.3 Solaris x86 注意事项 + 4.11.4 SunOS 4 注意事项 + 4.11.5 Linux (所有的Linux版本)注意事项
### 回答1: 在 protobuf ,可以使用嵌套消息类型来定义复杂的消息类型。例如,一个包含订单信息的消息类型可以被定义为: ``` syntax = "proto3"; message Order { string order_id = 1; repeated Item items = 2; Shipping shipping = 3; } message Item { string name = 1; int32 quantity = 2; float price = 3; } message Shipping { string address = 1; string city = 2; string state = 3; string zip_code = 4; } ``` 在上面的例子,Order 消息类型包含了一个字符串类型的订单 ID(order_id),一个 Item 消息类型的重复字段(items),以及一个 Shipping 消息类型的 shipping 字段。Item 消息类型包含了商品名称(name)、数量(quantity)和价格(price)字段。Shipping 消息类型包含了地址(address)、城市(city)、州(state)和邮政编码(zip_code)字段。 通过使用嵌套消息类型,可以轻松地定义复杂的消息类型,并且可以更好地组织数据结构,使其更易于维护和扩展。 ### 回答2: proto文件是Google开发的一种用于定义消息类型的语言。它可以帮助开发者在不同的平台和语言之间进行通信和数据交换。proto文件定义了复杂消息类型,使开发者可以在应用程序定义自己的数据结构和消息格式。 在proto文件,开发者可以定义各种数据类型,包括基本数据类型如整型、浮点型、布尔型,以及复杂数据类型如枚举、结构体等。通过定义这些数据类型,开发者可以根据自己的需求来创建各种复杂的消息类型。 使用proto文件定义复杂消息类型的好处是,它使得数据的传输和解析变得简单和可靠。proto文件消息类型可以被不同的编程语言自动转换为对应的数据结构,使得不同语言的应用程序可以直接交互和通信,而无需手动实现数据的序列化和反序列化。 另外,proto文件还支持消息类型的继承和嵌套,这使得开发者可以方便地定义更复杂的数据结构和消息类型。开发者可以通过继承机制来扩展已有的消息类型,也可以通过嵌套消息类型来定义更复杂的数据结构,进而满足不同应用场景的需求。 总之,proto文件是一种定义消息类型的强大工具,它可以帮助开发者定义复杂的数据结构和消息类型,实现不同应用程序之间的数据交换和通信。同时,它还提供了跨平台和跨语言的支持,使得开发更加简单和高效。 ### 回答3: proto文件是Google开发的一种用于定义和序列化结构化数据的语言。它可以用来定义复杂的消息类型,以便在不同的计算机系统之间进行数据交换。 在proto文件,我们可以定义不同的数据类型,包括基本数据类型(如整型、浮点型、布尔型等)以及复杂数据类型(如消息、枚举等)。对于复杂数据类型,我们可以使用嵌套的方式定义多层次的消息结构,从而构建出具有复杂关系和功能的消息类型。 通过proto文件定义复杂消息类型,我们可以明确指定消息的字段名称、类型和顺序,并可以选择性地添加字段的标记和选项。这样,在数据交换过程,发送方和接收方可以根据proto文件定义,准确地解析和处理消息,确保数据的一致性和准确性。 proto文件还支持使用扩展语法来定义可选的字段和特定领域(如自定义选项或插件)消息类型。这使得我们可以根据实际需求对消息进行灵活的定制,进一步增强了proto文件定义复杂消息类型的能力。 总之,通过proto文件定义复杂消息类型可以提供清晰明确的消息结构和定义,并且具有良好的跨平台和跨语言的兼容性。这让数据交换更加简单高效,从而提高了系统的可扩展性和可维护性。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值