Google Protobuf

1.Google Protobuf是什么?

Protobuf .是Google的语言无关,平台无关的可扩展机制,用于序列化结构化数据, 相比与 xml 等传统的序列化工具, 它更小、更快、更简单。
github地址:protobuf源码地址

优点:

  • 在谷歌内部长期使用, 产品成熟度高
  • 跨语言、支持多种语言, 包括 C++、Java 和 Python
  • 编码后的消息更小, 更加有利于存储和传输
  • 编解码的性能非常高
  • 支持不同协议版本的前向兼容
  • 支持定义可选和必选字段

2.ProtoBuf的使用

2.1 安装

protobuf的安装编译器使用的是c++,如果安装运行环境本身使用c++,可以直接按照c++的方式进行源码的编译和安装。如果不是c++环境,建议直接下载编译好的二进制文件。具体方法参看github地址:https://github.com/protocolbuffers/protobuf

2.2 结合Netty使用

Netty作为网络传输框架,结合protobuf序列化技术实现客户端和服务器的信息通信。
客户端使用protobuf将对象序列化成字节码,而服务器端通过protobuf将对象反序列化成原本对象。

2.2.1 定义.proto文件

syntax ="proto3";

option optimize_for = SPEED;
option java_package = "com.hosea.protobuf.nettydemo";
option java_outer_classname="DataInfo";

message RequestUser{
    optional string studentNo= 1;
    optional string password = 2;
}

message ResponseClass{
    optional string classNo= 1;
}

2.2.2 使用protoc进行编译

使用Protobuf编译器进行编译,生成DataInfo对象,将生成的类代码文件拷贝到相应工程中。

2.2.3 添加maven依赖

添加protobuf-java包依赖

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

2.2.4 客户端编码

public class ProtoClient {

    public static void main(String[] args) throws Exception{
        EventLoopGroup eventLoopGroup = new NioEventLoopGroup();

        try{
            Bootstrap bootstrap = new Bootstrap();
            bootstrap.group(eventLoopGroup).channel(NioSocketChannel.class)
                    .handler(new ProtoClientInitializer());

            ChannelFuture channelFuture = bootstrap.connect("localhost",8899).sync();
            channelFuture.channel().closeFuture().sync();

        }finally {
            eventLoopGroup.shutdownGracefully();
        }
    }
}


public class ProtoClientInitializer extends ChannelInitializer<SocketChannel> {

    @Override
    protected void initChannel(SocketChannel ch) throws Exception {
        ChannelPipeline pipeline = ch.pipeline();

        //解码器,通过Google Protocol Buffers序列化框架动态的切割接收到的ByteBuf
        pipeline.addLast(new ProtobufVarint32FrameDecoder());
        //将接收到的二进制文件解码成具体的实例,这边接收到的是服务端的ResponseClass对象实列
        pipeline.addLast(new ProtobufDecoder(DataInfo.ResponseClass.getDefaultInstance()));
        //Google Protocol Buffers编码器
        pipeline.addLast(new ProtobufVarint32LengthFieldPrepender());
        //Google Protocol Buffers编码器
        pipeline.addLast(new ProtobufEncoder());
        pipeline.addLast(new ProtoClientHandler());
    }
}


public class ProtoClientHandler extends SimpleChannelInboundHandler<DataInfo.ResponseBank> {

    @Override
    protected void channelRead0(ChannelHandlerContext ctx, DataInfo.ResponseClass msg) throws Exception {
        System.out.println(msg.getClassNo());
    }

    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        DataInfo.RequestUser user = DataInfo.RequestUser.newBuilder()                .setStudentNo("12345").setPassword("123456").build();
        ctx.channel().writeAndFlush(user);
    }
}

2.2.5 服务端编码

public class ProtoServer {
    public static void main(String[] args) throws Exception{
        EventLoopGroup bossGroup = new NioEventLoopGroup();
        EventLoopGroup wokerGroup = new NioEventLoopGroup();

        try{
            ServerBootstrap serverBootstrap = new ServerBootstrap();
            serverBootstrap.group(bossGroup,wokerGroup).channel(NioServerSocketChannel.class)
                    .handler(new LoggingHandler(LogLevel.INFO))
                    .childHandler(new ProtoServerInitializer());

            ChannelFuture channelFuture = serverBootstrap.bind(8899).sync();
            channelFuture.channel().closeFuture().sync();
        }finally {
            bossGroup.shutdownGracefully();
            wokerGroup.shutdownGracefully();
        }
    }
}




public class ProtoServerInitializer extends ChannelInitializer<SocketChannel>{

    @Override
    protected void initChannel(SocketChannel ch) throws Exception {
        ChannelPipeline pipeline = ch.pipeline();

        //解码器,通过Google Protocol Buffers序列化框架动态的切割接收到的ByteBuf
        pipeline.addLast(new ProtobufVarint32FrameDecoder());
        //服务器端接收的是客户端RequestUser对象,所以这边将接收对象进行解码生产实列
        pipeline.addLast(new ProtobufDecoder(DataInfo.RequestUser.getDefaultInstance()));
        //Google Protocol Buffers编码器
        pipeline.addLast(new ProtobufVarint32LengthFieldPrepender());
        //Google Protocol Buffers编码器
        pipeline.addLast(new ProtobufEncoder());
        pipeline.addLast(new ProtoServerHandler());
    }
}




public class ProtoServerHandler extends SimpleChannelInboundHandler<DataInfo.RequestUser> {

    @Override
    protected void channelRead0(ChannelHandlerContext ctx, DataInfo.RequestUser msg) throws Exception {
        System.out.println(msg.getStudentNo());
        System.out.println(msg.getPassword());

        DataInfo.ResponseClass class = DataInfo.ResponseClass.newBuilder().setClassNo("001701");
        ctx.channel().writeAndFlush(bank);
    }
}

3.总结

其实大多数RPC框架底层实现都是使用序列化框架和NIO通信框架进行结合。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值