Protocol Buffer整合netty

  • Post author:
  • Post category:其他




Protocol Buffer整合netty



1-1 前言

我们是在学习netty的背景下,学些protocol Buffer的,所以我们在我们的实践文档,也是在这样的背景下整理出来的。



1-2 编辑简单的Proco文件



1-2-1 Student .proto

syntax = "proto2";

package com.zt.proto;

option optimize_for = SPEED;
option java_package = "com.zt.proto";
option java_outer_classname = "MyDataInfo";

message Person {
  required string name =1;
  optional int32 age=2;
  optional string address=3;
}
  • syntax :指定使用的proto的版本 我们这里使用的是proto2

  • package :指定生成的java的类的包路径,如果 java_package不指定,就是这个目录

  • optimize_for:文件级别的选项,Protocol Buffer定义三种优化级别SPEED/CODE_SIZE/LITE_RUNTIME。缺省情况下是SPEED

  • SPEED:表示生成的代码运行效率高,但是由此生成的代码编译后会占用更多的空间。

  • CODE_SIZE: 和SPEED恰恰相反,代码运行效率较低,但是由此生成的代码编译后会占用更少的空间,通常用于资源有限的平台,如Mobile。

  • LITE_RUNTIME: 生成的代码执行效率高,同时生成代码编译后的所占用的空间也是非常少。这是以牺牲Protocol Buffer提供的反射功能为代价的。因此我们在C++中链接Protocol Buffer库时仅需链接libprotobuf-lite,而非libprotobuf。在Java中仅需包含protobuf-java-2.4.1-lite.jar,而非protobuf-java-2.4.1.jar。

  • java_package :表示生成的java类的包路径,官方建议,我们在编辑proto文件到额时候,最好还是指定。

  • java_outer_classname :表示生成的Java类的类名

  • message :指定一个消息协议

  • required:表示在传输数据的的时候这个字段为必须传输的数据。

  • optional:对应required,可选输出数据。

  • string 和int32 :还有其他的类型,指定的数据的类型

      可以在程序调试阶段使用 SPEED模式,而上线以后使用提升性能使用 LITE_RUNTIME 模式优化。
    



1-2-2 生成Java类和小测试

  • 生成的命令
protoc  --java_out=src\main\java src\protobuf\Student.proto 
  • 生成的java类

      生成的Java类有点大   这里就不贴出来。
    
  • 测试小程序

package com.zt.proto;

import com.google.protobuf.InvalidProtocolBufferException;

/**
 * @Description:
 * @Date: 2020/12/15 10:37
 * @author: zt
 */
public class ProtoBufTest {
    public static void main(String[] args) throws InvalidProtocolBufferException {
        MyDataInfo.Person person = MyDataInfo.Person.newBuilder()
                .setName("张山")
                .setAge(1111)
                .setAddress("成都")
                .build();

        byte[] bytes = person.toByteArray();
        // 字节数组可以网络传输  实现不同机子的远程过程调用
        MyDataInfo.Person person1 = MyDataInfo.Person.parseFrom(bytes);
        System.out.println(person1.getAddress());
        System.out.println(person1.getAge());
        System.out.println(person1.getName());
    }
}
  • 测试小程序的运行结果
成都
1111
张山

Process finished with exit code 0



1-3 整合netty和proco



1-3-1 proco文件

syntax = "proto2";

package com.zt.proto;

option optimize_for = SPEED;
option java_package = "com.zt.proto";
option java_outer_classname = "MyDataInfo";

message Person {
  required string name =1;
  optional int32 age=2;
  optional string address=3;
}



1-3-2 netty相关



1-3-2-1 TestServer

package com.zt.proto;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;

/**
 * @Description:
 * @Date: 2020/12/15 10:53
 * @author: zt
 */
public class TestServer {
    public static void main(String[] args) {
        NioEventLoopGroup bossGroup = new NioEventLoopGroup();
        NioEventLoopGroup workGroup = new NioEventLoopGroup();
        try {
            ServerBootstrap serverBootstrap = new ServerBootstrap();
            serverBootstrap.group(bossGroup,workGroup).channel(NioServerSocketChannel.class)
                    .handler(new LoggingHandler(LogLevel.INFO))
                    .childHandler(new TestInitializer());

            ChannelFuture channelFuture = serverBootstrap.bind(8899).sync();
            channelFuture.channel().closeFuture().sync();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }finally {
            bossGroup.shutdownGracefully();
            workGroup.shutdownGracefully();
        }
    }
}



1-3-2-2 TestInitializer

package com.zt.proto;

import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.socket.SocketChannel;
import io.netty.handler.codec.protobuf.ProtobufDecoder;
import io.netty.handler.codec.protobuf.ProtobufEncoder;
import io.netty.handler.codec.protobuf.ProtobufVarint32FrameDecoder;
import io.netty.handler.codec.protobuf.ProtobufVarint32LengthFieldPrepender;

/**
 * @Description:
 * @Date: 2020/12/15 10:59
 * @author: zt
 */
public class TestInitializer extends ChannelInitializer<SocketChannel> {

    @Override
    protected void initChannel(SocketChannel ch) throws Exception {
        ChannelPipeline pipeline = ch.pipeline();
        pipeline.addLast(new ProtobufVarint32FrameDecoder());
        pipeline.addLast(new ProtobufDecoder(MyDataInfo.Person.getDefaultInstance()));
        pipeline.addLast(new ProtobufVarint32LengthFieldPrepender());
        // 第一次没出现Bf shu'xua是ProtobufEncoder
        pipeline.addLast(new ProtobufEncoder());

        pipeline.addLast(new TestServerHandler());
    }
}



1-3-2-3 TestServerHandler

package com.zt.proto;

import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;

/**
 * @Description:
 * @Date: 2020/12/15 14:27
 * @author: zt
 */
public class TestServerHandler extends SimpleChannelInboundHandler<MyDataInfo.Person> {
    @Override
    protected void channelRead0(ChannelHandlerContext channelHandlerContext, MyDataInfo.Person person) throws Exception {
        System.out.println(person.getAddress());
        System.out.println(person.getAge());
        System.out.println(person.getName());
    }
}



1-3-2-4 TestClient

package com.zt.proto;

import io.netty.bootstrap.Bootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;

/**
 * @Description:
 * @Date: 2020/12/15 14:28
 * @author: zt
 */
public class TestClient {
    public static void main(String[] args) {
        EventLoopGroup eventLoopGroup = new NioEventLoopGroup();
        try {
            Bootstrap bootstrap = new Bootstrap();
            bootstrap.group(eventLoopGroup).channel(NioSocketChannel.class)
                    .handler(new TestClientInitializer());

            ChannelFuture channelFuture = bootstrap.connect("localhost", 8899).sync();
            channelFuture.channel().closeFuture().sync();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            eventLoopGroup.shutdownGracefully();
        }
    }

}



1-3-2-5 TestClientInitializer

package com.zt.proto;

import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.socket.SocketChannel;
import io.netty.handler.codec.protobuf.ProtobufDecoder;
import io.netty.handler.codec.protobuf.ProtobufEncoder;
import io.netty.handler.codec.protobuf.ProtobufVarint32FrameDecoder;
import io.netty.handler.codec.protobuf.ProtobufVarint32LengthFieldPrepender;

/**
 * @Description:
 * @Date: 2020/12/15 14:31
 * @author: zt
 */
public class TestClientInitializerextends ChannelInitializer<SocketChannel> {
    @Override
    protected void initChannel(SocketChannel ch) throws Exception {
        ChannelPipeline pipeline = ch.pipeline();
        pipeline.addLast(new ProtobufVarint32FrameDecoder());
        pipeline.addLast(new ProtobufDecoder(MyDataInfo.Person.getDefaultInstance()));
        pipeline.addLast(new ProtobufVarint32LengthFieldPrepender());
        pipeline.addLast(new ProtobufEncoder());

        pipeline.addLast(new TestClientHandler());
    }
}



1-3-2-6 TestClientHandler

package com.zt.proto;

import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;

/**
 * @Description:
 * @Date: 2020/12/15 14:37
 * @author: zt
 */
public class TestClientHandler extends SimpleChannelInboundHandler<MyDataInfo.Person> {
    @Override
    protected void channelRead0(ChannelHandlerContext channelHandlerContext, MyDataInfo.Person person) throws Exception {

    }

    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {

        MyDataInfo.Person person = MyDataInfo.Person.newBuilder()
                .setName("张山")
                .setAge(1111)
                .setAddress("成都")
                .build();

        ctx.channel().writeAndFlush(person);
        System.out.println("TestClientHandler:channelActive");
    }
}



1-3-2-7 pom文件补充

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>org.example</groupId>
    <artifactId>ProtocolDemo2</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <!--设置java的编译的jdk版本-->
        <maven.compiler.target>1.8</maven.compiler.target>
        <maven.compiler.source>1.8</maven.compiler.source>
        <protobufJavaVersion>3.11.0</protobufJavaVersion>
        <protobufJavaUtilVersion>3.11.0</protobufJavaUtilVersion>
        <nettyAllVersion>4.1.40.Final</nettyAllVersion>
    </properties>

    <dependencies>
        <dependency>
            <groupId>com.google.protobuf</groupId>
            <artifactId>protobuf-java</artifactId>
            <version>${protobufJavaVersion}</version>
        </dependency>
        <dependency>
            <groupId>com.google.protobuf</groupId>
            <artifactId>protobuf-java-util</artifactId>
            <version>${protobufJavaUtilVersion}</version>
        </dependency>
        <dependency>
            <groupId>io.netty</groupId>
            <artifactId>netty-all</artifactId>
            <version>${nettyAllVersion}</version>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                </configuration>
            </plugin>
        </plugins>
    </build>

</project>



1-3-2-8 简单说明下

netty相关的点,我这里就不赘述,前面的文档都有相关的说明。



1-3-3 测试和总结



1-3-3-1 server的日志

十二月 17, 2020 10:33:53 上午 io.netty.handler.logging.LoggingHandler channelRegistered
信息: [id: 0x916b2ebf] REGISTERED
十二月 17, 2020 10:33:53 上午 io.netty.handler.logging.LoggingHandler bind
信息: [id: 0x916b2ebf] BIND: 0.0.0.0/0.0.0.0:8899
十二月 17, 2020 10:33:53 上午 io.netty.handler.logging.LoggingHandler channelActive
信息: [id: 0x916b2ebf, L:/0:0:0:0:0:0:0:0:8899] ACTIVE
十二月 17, 2020 10:34:04 上午 io.netty.handler.logging.LoggingHandler channelRead
信息: [id: 0x916b2ebf, L:/0:0:0:0:0:0:0:0:8899] READ: [id: 0x07922e1b, L:/127.0.0.1:8899 - R:/127.0.0.1:59693]
十二月 17, 2020 10:34:04 上午 io.netty.handler.logging.LoggingHandler channelReadComplete
信息: [id: 0x916b2ebf, L:/0:0:0:0:0:0:0:0:8899] READ COMPLETE
成都
1111
张山



1-3-3-2 client的日志

TestClientHandler:channelActive



1-3-3-3 总结

  • 基本上程序是成功的运行了,我这里简单的说明下,在1-2小章节中我们写了小程序测试下,哪里我

    们是自己编码和解码,我们这个整合netty的时候,发现我们没有解码和编码,其实交给了netty帮我

    们 处理了。
  • 整合netty的大部分还是netty的部分,proco的部分编码还是没几行代码。
  • 我们这里是最的数据通信协议,要是我们存在多种数据通信协议,我们怎末处理?我会在后面整理出来。



版权声明:本文为qq_42641261原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。