zoukankan      html  css  js  c++  java
  • Netty--Google Protobuf编解码

    Google Protobuf是一种轻便高效的结构化数据存储格式,可以用于结构化数据序列化。它很适合做数据存储或 RPC 数据交换格式。可用于通讯协议、数据存储等领域的语言无关、平台无关、可扩展的序列化结构数据格式。

    编译安装:

    下载Java版 https://github.com/google/protobuf/releases

    tar -zxvf xxx.tar.gz

    ./configure

    make

    make install

    protoc --version

    mvn install

    mvn package

    使用:

    Google Protobuf支持复杂的POJO对象的编解码,而这些代码是自动生成的。

    首先写文件Person.proto ,定义程序中需要处理的结构化数据,在 protobuf 的中,结构化数据被称为 Message。

    syntax="proto3"; 
    package com.luangeng.netty.protobuf; 
    
    message Person { 
    string username=1; //
    int32 age=2; //
    string sex=3; //
    }

    执行命令

    protoc -I=. --java_out=. Person.proto

    格式: protoc -I=$SRC_DIR --cpp_out=$DST_DIR $SRC_DIR/***.proto

    即在当前目录下生成了Java文件PersonOutClass.java, 将它引入到工程并需要添加POM依赖

    <dependency>
        <groupId>com.google.protobuf</groupId>
        <artifactId>protobuf-java</artifactId>
        <version>3.5.0</version>
    </dependency>

    --

    然后做一个简单的编解码测试:

    public class TestProtoBuf {
    
        //编码为byte数组
        private static byte[] encoder(PersonOuterClass.Person p) {
            return p.toByteArray();
        }
    
        //从byte数组解码
        private static PersonOuterClass.Person decoder(byte[] b) throws InvalidProtocolBufferException {
            return PersonOuterClass.Person.parseFrom(b);
        }
    
        //使用builder实例来设置属性
        private static PersonOuterClass.Person create(){
            PersonOuterClass.Person.Builder builder = PersonOuterClass.Person.newBuilder();
            builder.setAge(10);
            builder.setSex("man");
            builder.setUsername("luangeng");
            return builder.build();
        }
    
        public static void main(String[] args) throws InvalidProtocolBufferException {
            PersonOuterClass.Person p = create();
            Q.p("before----------
    " + p.toString());
    
            PersonOuterClass.Person p2 = decoder(encoder(p));
            Q.p("afetr-----------
    " + p2.toString());
        }
    
    }

    ---

    输出结果:

    before----------
    username: "luangeng"
    age: 10
    sex: "man"

    afetr-----------
    username: "luangeng"
    age: 10
    sex: "man"

    在Netty中使用Google Protobuf实例:

    Server端:

    public class EchoServer {
        public static void main(String[] args) {
            new EchoServer().bind(8080);
        }
    
        public void bind(int port) {
            EventLoopGroup bossGroup = new NioEventLoopGroup();
            EventLoopGroup workerGroup = new NioEventLoopGroup();
            try {
                ServerBootstrap bootstrap = new ServerBootstrap();
                bootstrap.group(bossGroup, workerGroup)
                        .channel(NioServerSocketChannel.class)
                        .option(ChannelOption.SO_BACKLOG, 100)
                        .childHandler(new ChannelInitializer<SocketChannel>() {
                            @Override
                            protected void initChannel(SocketChannel ch) throws Exception {
                                ch.pipeline().addLast(new ProtobufVarint32FrameDecoder());
                                ch.pipeline().addLast(new ProtobufDecoder(PersonOuterClass.Person.getDefaultInstance()));
                                ch.pipeline().addLast(new ProtobufVarint32LengthFieldPrepender());
                                ch.pipeline().addLast(new ProtobufEncoder());
                                ch.pipeline().addLast(new EchoServerHandler());
                            }
                        });
                ChannelFuture future = bootstrap.bind(port).sync();
                System.out.println("server started");
                future.channel().closeFuture().sync();
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                System.out.println("server shuting down");
                bossGroup.shutdownGracefully();
                workerGroup.shutdownGracefully();
            }
        }
    }
    
    public class EchoServerHandler extends ChannelInboundHandlerAdapter {
        int count = 0;
    
        @Override
        public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
            PersonOuterClass.Person p = (PersonOuterClass.Person) msg;
            System.out.println("Server received " + count++ + " :
    " + p.toString());
            ctx.writeAndFlush(msg);
        }
    
        @Override
        public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
            cause.printStackTrace();
            ctx.close();
        }
    }

    ---

    Client端:

    public class EchoClient {
    
        public static void main(String[] args) {
            new EchoClient().connect("127.0.0.1", 8080);
        }
    
        public void connect(String host, int port) {
            EventLoopGroup group = new NioEventLoopGroup();
            try {
                Bootstrap bootstrap = new Bootstrap();
                bootstrap.group(group).channel(NioSocketChannel.class)
                        .option(ChannelOption.TCP_NODELAY, true)
                        .handler(new ChannelInitializer<SocketChannel>() {
                            protected void initChannel(SocketChannel ch) throws Exception {
                                ch.pipeline().addLast(new ProtobufVarint32FrameDecoder());
                                ch.pipeline().addLast(new ProtobufDecoder(PersonOuterClass.Person.getDefaultInstance()));
                                ch.pipeline().addLast(new ProtobufVarint32LengthFieldPrepender());
                                ch.pipeline().addLast(new ProtobufEncoder());
                                ch.pipeline().addLast(new EchoClientHandler());
                            }
                        });
                ChannelFuture future = bootstrap.connect(host, port).sync();
                System.out.println("client started");
                future.channel().closeFuture().sync();
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                System.out.println("client shuting down");
                group.shutdownGracefully();
            }
        }
    }
    
    public class EchoClientHandler extends ChannelInboundHandlerAdapter {
    
        private int count = 0;
    
        private static PersonOuterClass.Person create(int i) {
            PersonOuterClass.Person.Builder builder = PersonOuterClass.Person.newBuilder();
            builder.setAge(i);
            builder.setSex("man");
            builder.setUsername("luangeng" + i);
            return builder.build();
        }
    
        @Override
        public void channelActive(ChannelHandlerContext ctx) throws Exception {
            for (int i = 0; i < 20; i++) {
                ctx.writeAndFlush(create(i));
            }
        }
    
        //服务端返回应答信息后调用
        @Override
        public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
            PersonOuterClass.Person p = (PersonOuterClass.Person) msg;
            Q.p("Client get " + count++ + " :
    " + p.toString());
        }
    
        @Override
        public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
            ctx.flush();
        }
    
        @Override
        public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
            cause.printStackTrace();
            ctx.close();
        }
    }

    ---

    执行结果:

    client started
    Client get 0 :
    username: "luangeng0"
    sex: "man"

    Client get 1 :
    username: "luangeng1"
    age: 1
    sex: "man"

    Client get 2 :
    username: "luangeng2"
    age: 2
    sex: "man"

    Client get 3 :
    username: "luangeng3"
    age: 3
    sex: "man"

    Client get 4 :
    username: "luangeng4"
    age: 4
    sex: "man"

    Client get 5 :
    username: "luangeng5"
    age: 5
    sex: "man"

    Client get 6 :
    username: "luangeng6"
    age: 6
    sex: "man"

    Client get 7 :
    username: "luangeng7"
    age: 7
    sex: "man"

    Client get 8 :
    username: "luangeng8"
    age: 8
    sex: "man"

    Client get 9 :
    username: "luangeng9"
    age: 9
    sex: "man"

    Client get 10 :
    username: "luangeng10"
    age: 10
    sex: "man"

    Client get 11 :
    username: "luangeng11"
    age: 11
    sex: "man"

    Client get 12 :
    username: "luangeng12"
    age: 12
    sex: "man"

    Client get 13 :
    username: "luangeng13"
    age: 13
    sex: "man"

    Client get 14 :
    username: "luangeng14"
    age: 14
    sex: "man"

    Client get 15 :
    username: "luangeng15"
    age: 15
    sex: "man"

    end

  • 相关阅读:
    多线程使用常识
    《30天自制操作系统》实现中文显示
    DDD实践(一)
    为了钱这是很正当的,我跟你干,我要获得一个好的收入,我要改善我的生活,我要提高我的生活质量(转)
    Java对象序列化/反序列化的注意事项(转)
    Java使用Socket传输文件遇到的问题(转)
    大胆采用开源工具(转)
    如果常量类进行改变时,只编译常量类,而使用常量的类不重新编码,这样改动实际上算没有生效(转)
    在html中写python代码的语法和特点-----基于webpy的httpserver
    在Activity中为什么要用managedQuery()
  • 原文地址:https://www.cnblogs.com/luangeng/p/7881511.html
Copyright © 2011-2022 走看看