zoukankan      html  css  js  c++  java
  • Netty使用Google Protocol Buffer完成服务器高性能数据传输

    一、什么是Google Protocol Buffer(protobuf官方网站

    下面是官网给的解释:
    Protocol buffers are a language-neutral, platform-neutral extensible mechanism for serializing structured data. – think XML, but smaller, faster, and simpler.
    协议缓冲区是一种和语言无关、平台无关的可扩展机制,用于序列化结构化的数据。相比于xml,它更小,更快,更简单。数据缓冲区常用语通信协议和数据存储。

    二、ProtoBuf的性能

    序列化测试对比:
    Ser Time + Deser Time(ns)

    下面两个网站是效率测试实验:

    三、使用Intellij IDEA插件自动生成Java类

    参考我的另一篇文章:Google Protocol Buffer 的使用(一)

    四、Netty和protobuf整合

    准备我们的proto文件

    syntax = "proto3";
    package com.netty.protobuf;
    option java_outer_classname = "UserInfoProto";
    
    //用户信息
    message UserInfo{
        //姓名
        string name = 1;
        //住址
        repeated Address address= 2;
        //年龄
        uint32 age = 3;
    }
    
    //用户常用住址
    message Address{
        string addressname = 1;
        uint32 adressno = 2;
    }
    

    服务器中设置protobuf编码器和解码器

    @Override
    protected void initChannel(SocketChannel ch) throws Exception {
        ChannelPipeline pipeline = ch.pipeline();
        //protobuf解码器
        pipeline.addLast(new ProtobufVarint32FrameDecoder());
        pipeline.addLast(new ProtobufDecoder(UserInfoProto.UserInfo.getDefaultInstance()));
        //protobuf编码器
        pipeline.addLast(new ProtobufVarint32LengthFieldPrepender());
        pipeline.addLast(new ProtobufEncoder());
        pipeline.addLast(new NettyServerHandler());
    }
    
    • ProtobufVarint32FrameDecoder是protobuf方式的解码器,用于解决TCP粘包和拆包问题
    • ProtobufDecoder 中设置我们的proto文件生成的实例,其实就是我们的目标Java类,设置方式为:UserInfoProto.UserInfo.getDefaultInstance()
    • ProtobufVarint32LengthFieldPrepender和ProtobufEncoder是protobuf方式的编码器

    处理类中写protobuf数据

        @Override
        public void channelActive(ChannelHandlerContext ctx) throws Exception {
            LOGGER.info("client {} connected.", ctx.channel().remoteAddress());
            UserInfoProto.UserInfo user = UserInfoProto.UserInfo.newBuilder()
                    .setName("server")
                    .setAge(18)
                    .addAddress(
                            UserInfoProto.Address.newBuilder()
                                    .setAddressname("beijing 001")
                                    .setAdressno(911))
                    .build();
            ctx.writeAndFlush(user);
        }
    
    • 这里通过UserInfoProto.UserInfo.newBuilder()使用的时间其类的建造者模式设置用户相关信息。
    • 再通过ChannelHandlerContext的writeAndFlush方法写用户数据。

    处理器中读protobuf数据

        private int count = 0;
        @Override
        public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
            UserInfoProto.UserInfo message = (UserInfoProto.UserInfo) msg;
            LOGGER.info("server received message {}:{}", ++count, message);
        }
    
    • channelRead中的Object对象通过解码之后就是一个protobuf类对象,所以可以强转:UserInfoProto.UserInfo message = (UserInfoProto.UserInfo) msg;

    五、注意事项(TCP读半包处理)

    这里我们只是简单使用了netty自带的ProtobufVarint32FrameDecoder解码器来处理读半包问题,我们还可以自己继承ByteToMessageDecoder类实现一个定制化的解码器。比如我们使用Java客户端和C++服务器通过protobuf协议来通信时,就需要自己实现,同时还需要考虑大端、小端模式的转换问题。

  • 相关阅读:
    python Elementtree 生成带缩进格式的xml文件
    Tacotron2论文阅读笔记
    opencv3 7.3 重映射 仿射变换
    numpy.ndarray类型方法
    ubuntu安装百度输入法
    gitlab--cicd实践pytest和flask接口化
    django搭建完毕运行显示hello django
    django搭建
    服务器内存
    python安装第三方库aiohtpp,sanio失败,pip install multidict 失败问题
  • 原文地址:https://www.cnblogs.com/monkjavaer/p/11216084.html
Copyright © 2011-2022 走看看