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);
    
    
        }
    }
  • 相关阅读:
    LeetCode 88. Merge Sorted Array
    LeetCode 75. Sort Colors
    LeetCode 581. Shortest Unsorted Continuous Subarray
    LeetCode 20. Valid Parentheses
    LeetCode 53. Maximum Subarray
    LeetCode 461. Hamming Distance
    LeetCode 448. Find All Numbers Disappeared in an Array
    LeetCode 976. Largest Perimeter Triangle
    LeetCode 1295. Find Numbers with Even Number of Digits
    如何自学并且系统学习计算机网络?(知乎问答)
  • 原文地址:https://www.cnblogs.com/hyy9527/p/13100896.html
Copyright © 2011-2022 走看看