关于java:Netty-使用-Protobuf-序列化太强大了

31次阅读

共计 5409 个字符,预计需要花费 14 分钟才能阅读完成。

作者:rickiyang

出处:www.cnblogs.com/rickiyang/p/11074232.html

咱们来应用 Protobuf 进行序列化,它和 XML,json 一样都有本人的语法,xml 的后缀是.xml,json 文件的后缀是.json,天然 Protobuf 文件的后缀就是.proto(哈哈,当然不是全称)。

上面咱们应用 Protobuf 来封装一段音讯,通过一个案例简略介绍一下它的应用。

首先咱们用 Protobuf 的语法格局来写一段须要序列化的对象,命名格局为:Msg.proto

option java_package = "cn.edu.hust.netty.demo10";
option java_outer_classname = "MessageProto";

message RequestMsg{
    required bytes msgType = 1;
    required string receiveOne = 2;
    required string msg = 3;
}

message ResponseMsg{
    required bytes msgType = 1;
    required string receiveOne = 2;
    required string msg = 3;
}

对于 Message.proto 中的语法格局,详情大家 google 一下相干的阐明,网上很多介绍,再次简略就下面的语法阐明一下:

  • option java_package:示意生成的.java 文件的包名
  • option java_outer_classname:生成的 java 文件的文件名
  • message:为他的根本类型,如同 java 中的 class 一样

字段修饰符:

  • required:一个格局良好的音讯肯定要含有 1 个这种字段。示意该值是必须要设置的;
  • optional:音讯格局中该字段能够有 0 个或 1 个值(不超过 1 个)。
  • repeated:在一个格局良好的音讯中,这种字段能够反复任意屡次(包含 0 次)。反复的值的程序会被保留。示意该值能够反复,相当于 java 中的 List。

字符类型略微有些不同:double,float,int32,int64,bool(boolean),string,bytes。略微有些不同,String,boolean,int 有差异。

另外咱们看到下面 3 个字段别离赋值了,这个值是什么意思呢?音讯定义中,每个字段都有惟一的一个 数字标识符 。这些标识符是用来在音讯的二进制格局中辨认各个字段的,一旦开始应用就不可能再扭转。注:[1,15] 之内的标识号在编码的时候会占用一个字节。[16,2047]之内的标识号则占用 2 个字节。所以应该为那些频繁呈现的音讯元素保留 [1,15]之内的标识号。

对于 Protobuf 的语法咱们就简略的介绍这么多,更多细节大家本人去查阅文档吧。上面咱们开始应用 Protobuf 来进行序列化。

首先咱们的在工程中引入 protobuf 的 jar 包,目前官网版本最高 3.2,咱们用 3.0 的吧:

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

Protobuf 的文件曾经定义好了,下就须要把它编译成 java 代码,这里咱们的借助到 google 为咱们提供的脚本工具 protoc,链接在这里,点击下载这里提供的是 protoc-3.0.2。要留神 protoc 的版本须要和 Protobuf 的版本对应上,不然不同的版本之间会有一些差别解析可能会有问题。当初晓得咱们为啥非得选用 protobuf3.0.2 版本吧,因为我没有找到别的版本的 protoc。。。

下载好了咱们解压缩而后把方才写好的 Msg.proto 文件复制进去。

接着咱们进 cmd 输出如下命令:

次要是第三句命令。如果你输出没有报错的话你的 proto 文件夹应该会生成一个子文件夹:

进去该文件夹你会看到曾经生成了 MessageProto.java 文件,祝贺你,这时候你曾经实现了 protobuf 序列化文件的生成。而后你把该文件拷贝至工程目录下

接下来咱们用生成的文件去发消息吧。还是老套路服务端和客户端。

服务端:

public class ProtoBufServer {
    private int port;

    public ProtoBufServer(int port) {this.port = port;}

    public void start(){EventLoopGroup bossGroup = new NioEventLoopGroup();
        EventLoopGroup workGroup = new NioEventLoopGroup();

        ServerBootstrap server = new ServerBootstrap().group(bossGroup,workGroup)
                                    .channel(NioServerSocketChannel.class)
                                    .childHandler(new ServerChannelInitializer());

        try {ChannelFuture future = server.bind(port).sync();
            future.channel().closeFuture().sync();} catch (InterruptedException e) {e.printStackTrace();
        }finally {bossGroup.shutdownGracefully();
            workGroup.shutdownGracefully();}
    }

    public static void main(String[] args) {ProtoBufServer server = new ProtoBufServer(7788);
        server.start();}
}

服务端 Initializer:

public class ServerChannelInitializer extends ChannelInitializer<SocketChannel> {
    @Override
    protected void initChannel(SocketChannel socketChannel) throws Exception {ChannelPipeline pipeline = socketChannel.pipeline();

        pipeline.addLast(new ProtobufVarint32FrameDecoder());
        pipeline.addLast(new ProtobufDecoder(MessageProto.RequestMsg.getDefaultInstance()));
        pipeline.addLast(new ProtoBufServerHandler());
    }
}

服务端 handler:

public class ProtoBufServerHandler extends ChannelInboundHandlerAdapter {
    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {MessageProto.ResponseMsg.Builder builder = MessageProto.ResponseMsg.newBuilder();
        builder.setMsgType(ByteString.copyFromUtf8("CBSP"));
        builder.setReceiveOne("小红");
        builder.setMsg("你好,你有啥事");

        ctx.writeAndFlush(builder.build());
    }


    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {MessageProto.RequestMsg m = (MessageProto.RequestMsg)msg;
        System.out.println("Client say:"+m.getReceiveOne()+","+m.getMsg());
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {super.exceptionCaught(ctx, cause);
        ctx.close();}
}

客户端:

public class ProtoBufClient {
    private  int port;
    private  String address;

    public ProtoBufClient(int port, String address) {
        this.port = port;
        this.address = address;
    }

    public void start(){EventLoopGroup group = new NioEventLoopGroup();

        Bootstrap bootstrap = new Bootstrap();
        bootstrap.group(group)
                .channel(NioSocketChannel.class)
                .handler(new ClientChannelInitializer());

        try {ChannelFuture future = bootstrap.connect(address,port).sync();
            future.channel().closeFuture().sync();} catch (Exception e) {e.printStackTrace();
        }finally {group.shutdownGracefully();
        }

    }

    public static void main(String[] args) {ProtoBufClient client = new ProtoBufClient(7788,"127.0.0.1");
        client.start();}
}

客户端 Initializer:

public class ClientChannelInitializer extends  ChannelInitializer<SocketChannel> {protected void initChannel(SocketChannel socketChannel) throws Exception {ChannelPipeline pipeline = socketChannel.pipeline();

        pipeline.addLast(new ProtobufVarint32LengthFieldPrepender());
        pipeline.addLast(new ProtobufEncoder());
        pipeline.addLast(new ProtoBufClientHandler());
    }
}

客户端 handler:public class ProtoBufClientHandler extends ChannelInboundHandlerAdapter {
    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {MessageProto.ResponseMsg m = (MessageProto.ResponseMsg)msg;
        System.out.println("Server say:"+m.getReceiveOne()+","+m.getMsg());
    }

    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {MessageProto.RequestMsg.Builder builder = MessageProto.RequestMsg.newBuilder();
        builder.setMsgType(ByteString.copyFromUtf8("CBSP"));
        builder.setReceiveOne("小明");
        builder.setMsg("你好,我找你有事");

        ctx.writeAndFlush(builder.build());
    }

    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {System.out.println("Client is close");
    }
}

启动服务端和客户端,输入如下:

最简略的 protoBuf 利用案例咱们就写完了,实在的应用场景大同小异,随机应变即可。

近期热文举荐:

1.1,000+ 道 Java 面试题及答案整顿(2021 最新版)

2. 终于靠开源我的项目弄到 IntelliJ IDEA 激活码了,真香!

3. 阿里 Mock 工具正式开源,干掉市面上所有 Mock 工具!

4.Spring Cloud 2020.0.0 正式公布,全新颠覆性版本!

5.《Java 开发手册(嵩山版)》最新公布,速速下载!

感觉不错,别忘了顺手点赞 + 转发哦!

正文完
 0