zoukankan      html  css  js  c++  java
  • Protobuf

    1.Protobuf基本介绍和使用示意图

    • Protobuf 是 Google 发布的开源项目,全称 Google Protocol Buffers,是一种轻便高效的结构化数据存储格式,可以用于结构化数据串行化,或者说序列化。它很适合做数据存储或 RPC[远程过程调用 remote procedure call ] 数据交换格式 。目前很多公司 http+json  tcp+protobuf.
    • 参考文档 : https://developers.google.com/protocol-buffers/docs/proto 语言指南.
    • Protobuf 是以 message 的方式来管理数据的.
    • 支持跨平台、跨语言,即[客户端和服务器端可以是不同的语言编写的(支持目前绝大多数语言,例如 C++、C#、Java、python 等)

    2.Protobuf使用示意图

     

    3.代码

    1.编写.proto文件

    //版本号
    syntax = "proto3";
    //加快解析
    option optimize_for = SPEED; // 加快解析
    //指定生成包下
    //option java_package="com.hyy.netty.proto.moreObj";
    //外部类名
    option java_outer_classname = "MyData";
    //内部类-1
    message Student {
        int32 id = 1; //属性,java的int类型
        string name = 2; //java的String类型
    }
    //内部类-2
    message Worker {
        string name = 1; //java的String类型
        int32 id = 2; //属性,java的int类型
    }
    //内部类-3,用来管理其他类型
    message MyMessage {
        //定义枚举类
        enum DataType {
            StudentType = 0; //在proto3中枚举从0开始
            WorkerType = 1;
        }
        //用来标识传的是哪个枚举类型
        DataType date_type = 1;
        //每次只能出现一个枚举类型
        oneof dataOneType {
            Student student = 2;
            Worker worker = 3;
        }
    
    }

    2.使用protoc.exe编译后的java文件(部分)

    public final class MyData {
      private MyData() {}
      public static void registerAllExtensions(
          com.google.protobuf.ExtensionRegistryLite registry) {
      }
    .....代码过长,省略
    }

    3.服务端

    public class MyServer {
        public static void main(String[] args) throws InterruptedException {
            NioEventLoopGroup boss = new NioEventLoopGroup();
            NioEventLoopGroup worker = new NioEventLoopGroup();
         try{
             ServerBootstrap serverBootstrap=new ServerBootstrap();
             serverBootstrap.group(boss,worker)
                     .channel(NioServerSocketChannel.class)
                     .childHandler(new ChannelInitializer<SocketChannel>() {
                         @Override
                         protected void initChannel(SocketChannel ch) throws Exception {
                             ChannelPipeline pipeline = ch.pipeline();
                             /**
                              * 加入谷歌解码器ProtobufDecoder,需要指定对象
                              * ProtobufDecoder(MyDataInfo.Student.getDefaultInstance())
                              * 指定类的内部类对象
                              */
                             pipeline.addLast(new ProtobufDecoder(MyData.MyMessage.getDefaultInstance()));
                             pipeline.addLast(new ServerHandler());
                         }
                     });
             ChannelFuture channelFuture = serverBootstrap.bind(7000).sync();
             channelFuture.channel().closeFuture().sync();
    
         }finally {
             boss.shutdownGracefully();
             worker.shutdownGracefully();
    
         }
    
        }
    }

    4.服务端处理类

    public class ServerHandler extends SimpleChannelInboundHandler<MyData.MyMessage> {
    
        /**
         *
         * 读取数据实际(这里我们可以读取客户端发送的消息)
         * @param ctx the {@link ChannelHandlerContext} which this {@link SimpleChannelInboundHandler}
         *            belongs to
         * @param msg the message to handle
         * @throws Exception is thrown if an error occurred
         */
        @Override
        protected void channelRead0(ChannelHandlerContext ctx, MyData.MyMessage msg) throws Exception {
            //根据客户端定义的DataType,显示不同的信息
            MyData.MyMessage.DataType dataType=msg.getDateType();
            if (dataType==MyData.MyMessage.DataType.StudentType){
                MyData.Student student=msg.getStudent();
                System.out.println("学生名字:"+student.getName()+",学生ID:"+student.getId());
    
            }else if (dataType==MyData.MyMessage.DataType.WorkerType){
                MyData.Worker worker=msg.getWorker();
                System.out.println("工人名字:"+worker.getName()+",工人ID:"+worker.getId());
    
            }else {
                System.out.println("类型不对");
            }
    
        }
    
        @Override
        public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
    
            //writeAndFlush 是 write + flush
            //将数据写入到缓存,并刷新
            //一般讲,我们对这个发送的数据进行编码
            //发送给客户端消息
            ctx.writeAndFlush(Unpooled.copiedBuffer("hello, 客户端!!!!我是服务端.......", CharsetUtil.UTF_8));
        }
    
        //处理异常, 一般是需要关闭通道
    
        @Override
        public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
            ctx.close();
        }
    }

    5.客户端

    public class MyClient {
        public static void main(String[] args) throws InterruptedException {
            //创建一个事件循环组
            NioEventLoopGroup eventExecutors = new NioEventLoopGroup();
            try {
                Bootstrap bootstrap = new Bootstrap();
                bootstrap.group(eventExecutors)
                        .channel(NioSocketChannel.class)
                        .handler(new ChannelInitializer<SocketChannel>() {
                            @Override
                            protected void initChannel(SocketChannel ch) throws Exception {
                                ChannelPipeline pipeline = ch.pipeline();
                                //加入谷歌编码器
                                pipeline.addLast(new ProtobufEncoder());
                                //加入自定义处理类
                                pipeline.addLast(new MyClientHandler());
                            }
                        });
                ChannelFuture channelFuture = bootstrap.connect("127.0.0.1", 7000).sync();
                //监视关闭
                channelFuture.channel().closeFuture().sync();
            } finally {
                eventExecutors.shutdownGracefully();
            }
    
        }
    }

    6.客户端处理类

    public class MyClientHandler extends ChannelInboundHandlerAdapter {
        //当通道就绪就会触发该方法
        @Override
        public void channelActive(ChannelHandlerContext ctx) throws Exception {
            //随机发送Student/worker对象
            int random = new Random().nextInt(3);
            MyData.MyMessage myMessage = null;
            if (0 == random) {
                myMessage = MyData.MyMessage.newBuilder()
                        .setDateType(MyData.MyMessage.DataType.StudentType)
                        .setStudent(MyData.Student.newBuilder().setId(1).setName("张三"))
                        .build();
            } else {
                myMessage = MyData.MyMessage.newBuilder()
                        .setDateType(MyData.MyMessage.DataType.WorkerType)
                        .setWorker(MyData.Worker.newBuilder().setId(2).setName("李四"))
                        .build();
    
            }
            ctx.writeAndFlush(myMessage);
    
    
        }
    }
  • 相关阅读:
    mysql数据库存放路径
    mysql 5.5安装不对容易出现问题
    bean的scope属性
    spring四种依赖注入方式
    spring依赖注入(反转控制)
    Tomcat 安装错误
    synchronized详解
    git tag命令
    vjson.hpp
    cmake添加版本号
  • 原文地址:https://www.cnblogs.com/hyy9527/p/13100896.html
Copyright © 2011-2022 走看看