[Netty学习笔记]九、ProtoBuf的入门使用

概述

通过前面的学习,我们了解到数据在网络中传输的都是二进制字节码数据,因而在发送数据时就需要编码,接收数据时就需要解码。

codec(编解码器)的组成部分有两个:decoder(解码器)和encoder(编码器)。encoder负责把业务数据转换成字节码数据,decoder负责把字节码数据转换成业务数据

Netty中本身也提供了一些编解码器,如:

  • StringEncoder/StringDecoder 对字符串进行编解码
  • ObjectEncoder/ObjectDecoder 对Java对象进行编解码

通过了解可以发现,Netty编解码器底层使用Java序列化技术来实现的。 但是Java序列化技术本身效率不高,而且无法跨语言,序列化后的体积太大(是二进制编码的5倍多),序列化性能太低。因此转而选择使用ProtoBuf来实现序列化。

ProtoBuf的优点/特性:

  1. ProtiBuf以message的方式来管理数据
  2. 支持跨平台、跨语言
  3. 高性能、高可靠性
  4. 适合做数据存储或RPC
ProtoBuf的使用

使用步骤:

1、引入ProtoBuf依赖

2、编写.proto文件

3、使用protoc编译器将.proto文件自动生成为对应语言的文件(也可使用grpc来自动生成)

下面创建一个简单的proto文件并自动生成为Java文件:

1、引入3.6.1版本的依赖

 <dependency>
            <groupId>com.google.protobufgroupId>
            <artifactId>protobuf-javaartifactId>
            <version>3.6.1version>
  dependency>

2、编写Student.proto文件(IDEA的话 可以装Proto插件)

syntax = "proto3"; //版本

option java_outer_classname = "StudentPOJO"; //生成的外部类名 同时也是文件名
//protobuf使用message管理数据
message Student { //会在StudentPOJO外部类生成一个内部类Student,真正用到的对象
      int32 id=1;//student类中有一个属性 名字为id 类型为int32(protibuf类型) 1表示属性序号
      string name=2;
			
}

如上创建一个proto文件,Student类是真正用到的对象,将是以一个内部类的方式展现在Java文件中,其中定义了两个成员变量:int id;String name。

3、使用编译器编译proto文件

注意:这里依赖的protobuf是3.6.1版本,因此编译器也要是3.6.1版本的,我这里下载的是osx-3.6.1版本的

protoc编译器下载

由于这里使用的是Java语言,因此执行命令如下:

将Student.proto文件拷贝到protoc编译器同级目录

protoc --java_out=. Student.proto

生成的StudengPOJO.Java文件如下:

// Generated by the protocol buffer compiler.  DO NOT EDIT!
// source: Student.proto

public final class StudentPOJO {
  private StudentPOJO() {}
  public static void registerAllExtensions(
      com.google.protobuf.ExtensionRegistryLite registry) {
  }

  public static void registerAllExtensions(
      com.google.protobuf.ExtensionRegistry registry) {
    registerAllExtensions(
        (com.google.protobuf.ExtensionRegistryLite) registry);
  }
  public interface StudentOrBuilder extends
      // @@protoc_insertion_point(interface_extends:Student)
      com.google.protobuf.MessageOrBuilder {

    /**
     * 
     *student类中有一个属性 名字为id 类型为int32(protibuf类型) 1表示属性序号
     * 
* * int32 id = 1; */
int getId(); /** * string name = 2; */ String getName(); /** * string name = 2; */ com.google.protobuf.ByteString getNameBytes(); } /** *
   *protobuf使用message管理数据
   * 
* * Protobuf type {@code Student} */
public static final class Student extends com.google.protobuf.GeneratedMessageV3 implements // @@protoc_insertion_point(message_implements:Student) StudentOrBuilder { private static final long serialVersionUID = 0L; // Use Student.newBuilder() to construct. private Student(com.google.protobuf.GeneratedMessageV3.Builder<?> builder) { super(builder); } private Student() { id_ = 0; name_ = ""; } @Override public final com.google.protobuf.UnknownFieldSet getUnknownFields() { return this.unknownFields; } private Student( com.google.protobuf.CodedInputStream input, com.google.protobuf.ExtensionRegistryLite extensionRegistry) throws com.google.protobuf.InvalidProtocolBufferException { this(); if (extensionRegistry == null) { throw new NullPointerException(); } int mutable_bitField0_ = 0; com.google.protobuf.UnknownFieldSet.Builder unknownFields = com.google.protobuf.UnknownFieldSet.newBuilder(); try { boolean done = false; while (!done) { int tag = input.readTag(); switch (tag) { case 0: done = true; break; case 8: { id_ = input.readInt32(); break; } case 18: { String s = input.readStringRequireUtf8(); name_ = s; break; } default: { if (!parseUnknownFieldProto3( input, unknownFields, extensionRegistry, tag)) { done = true; } break; } } } } catch (com.google.protobuf.InvalidProtocolBufferException e) { throw e.setUnfinishedMessage(this); } catch (java.io.IOException e) { throw new com.google.protobuf.InvalidProtocolBufferException( e).setUnfinishedMessage(this); } finally { this.unknownFields = unknownFields.build(); makeExtensionsImmutable(); } } public static final com.google.protobuf.Descriptors.Descriptor getDescriptor() { return StudentPOJO.internal_static_Student_descriptor; } @Override protected FieldAccessorTable internalGetFieldAccessorTable() { return StudentPOJO.internal_static_Student_fieldAccessorTable .ensureFieldAccessorsInitialized( Student.class, Builder.class); } public static final int ID_FIELD_NUMBER = 1; private int id_; /** *
     *student类中有一个属性 名字为id 类型为int32(protibuf类型) 1表示属性序号
     * 
* * int32 id = 1; */
public int getId() { return id_; } public static final int NAME_FIELD_NUMBER = 2; private volatile Object name_; /** * string name = 2; */ public String getName() { Object ref = name_; if (ref instanceof String) { return (String) ref; } else { com.google.protobuf.ByteString bs = (com.google.protobuf.ByteString) ref; String s = bs.toStringUtf8(); name_ = s; return s; } } /** * string name = 2; */ public com.google.protobuf.ByteString getNameBytes() { Object ref = name_; if (ref instanceof String) { com.google.protobuf.ByteString b = com.google.protobuf.ByteString.copyFromUtf8( (String) ref); name_ = b; return b; } else { return (com.google.protobuf.ByteString) ref; } } private byte memoizedIsInitialized = -1; @Override public final boolean isInitialized() { byte isInitialized = memoizedIsInitialized; if (isInitialized == 1) return true; if (isInitialized == 0) return false; memoizedIsInitialized = 1; return true; } @Override public void writeTo(com.google.protobuf.CodedOutputStream output) throws java.io.IOException { if (id_ != 0) { output.writeInt32(1, id_); } if (!getNameBytes().isEmpty()) { com.google.protobuf.GeneratedMessageV3.writeString(output, 2, name_); } unknownFields.writeTo(output); } @Override public int getSerializedSize() { int size = memoizedSize; if (size != -1) return size; size = 0; if (id_ != 0) { size += com.google.protobuf.CodedOutputStream .computeInt32Size(1, id_); } if (!getNameBytes().isEmpty()) { size += com.google.protobuf.GeneratedMessageV3.computeStringSize(2, name_); } size += unknownFields.getSerializedSize(); memoizedSize = size; return size; } @Override public boolean equals(final Object obj) { if (obj == this) { return true; } if (!(obj instanceof Student)) { return super.equals(obj); } Student other = (Student) obj; boolean result = true; result = result && (getId() == other.getId()); result = result && getName() .equals(other.getName()); result = result && unknownFields.equals(other.unknownFields); return result; } @Override public int hashCode() { if (memoizedHashCode != 0) { return memoizedHashCode; } int hash = 41; hash = (19 * hash) + getDescriptor().hashCode(); hash = (37 * hash) + ID_FIELD_NUMBER; hash = (53 * hash) + getId(); hash = (37 * hash) + NAME_FIELD_NUMBER; hash = (53 * hash) + getName().hashCode(); hash = (29 * hash) + unknownFields.hashCode(); memoizedHashCode = hash; return hash; } public static Student parseFrom( java.nio.ByteBuffer data) throws com.google.protobuf.InvalidProtocolBufferException { return PARSER.parseFrom(data); } public static Student parseFrom( java.nio.ByteBuffer data, com.google.protobuf.ExtensionRegistryLite extensionRegistry) throws com.google.protobuf.InvalidProtocolBufferException { return PARSER.parseFrom(data, extensionRegistry); } public static Student parseFrom( com.google.protobuf.ByteString data) throws com.google.protobuf.InvalidProtocolBufferException { return PARSER.parseFrom(data); } public static Student parseFrom( com.google.protobuf.ByteString data, com.google.protobuf.ExtensionRegistryLite extensionRegistry) throws com.google.protobuf.InvalidProtocolBufferException { return PARSER.parseFrom(data, extensionRegistry); } public static Student parseFrom(byte[] data) throws com.google.protobuf.InvalidProtocolBufferException { return PARSER.parseFrom(data); } public static Student parseFrom( byte[] data, com.google.protobuf.ExtensionRegistryLite extensionRegistry) throws com.google.protobuf.InvalidProtocolBufferException { return PARSER.parseFrom(data, extensionRegistry); } public static Student parseFrom(java.io.InputStream input) throws java.io.IOException { return com.google.protobuf.GeneratedMessageV3 .parseWithIOException(PARSER, input); } public static Student parseFrom( java.io.InputStream input, com.google.protobuf.ExtensionRegistryLite extensionRegistry) throws java.io.IOException { return com.google.protobuf.GeneratedMessageV3 .parseWithIOException(PARSER, input, extensionRegistry); } public static Student parseDelimitedFrom(java.io.InputStream input) throws java.io.IOException { return com.google.protobuf.GeneratedMessageV3 .parseDelimitedWithIOException(PARSER, input); } public static Student parseDelimitedFrom( java.io.InputStream input, com.google.protobuf.ExtensionRegistryLite extensionRegistry) throws java.io.IOException { return com.google.protobuf.GeneratedMessageV3 .parseDelimitedWithIOException(PARSER, input, extensionRegistry); } public static Student parseFrom( com.google.protobuf.CodedInputStream input) throws java.io.IOException { return com.google.protobuf.GeneratedMessageV3 .parseWithIOException(PARSER, input); } public static Student parseFrom( com.google.protobuf.CodedInputStream input, com.google.protobuf.ExtensionRegistryLite extensionRegistry) throws java.io.IOException { return com.google.protobuf.GeneratedMessageV3 .parseWithIOException(PARSER, input, extensionRegistry); } @Override public Builder newBuilderForType() { return newBuilder(); } public static Builder newBuilder() { return DEFAULT_INSTANCE.toBuilder(); } public static Builder newBuilder(Student prototype) { return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); } @Override public Builder toBuilder() { return this == DEFAULT_INSTANCE ? new Builder() : new Builder().mergeFrom(this); } @Override protected Builder newBuilderForType( BuilderParent parent) { Builder builder = new Builder(parent); return builder; } /** *
     *protobuf使用message管理数据
     * 
* * Protobuf type {@code Student} */
public static final class Builder extends com.google.protobuf.GeneratedMessageV3.Builder<Builder> implements // @@protoc_insertion_point(builder_implements:Student) StudentOrBuilder { public static final com.google.protobuf.Descriptors.Descriptor getDescriptor() { return StudentPOJO.internal_static_Student_descriptor; } @Override protected FieldAccessorTable internalGetFieldAccessorTable() { return StudentPOJO.internal_static_Student_fieldAccessorTable .ensureFieldAccessorsInitialized( Student.class, Builder.class); } // Construct using StudentPOJO.Student.newBuilder() private Builder() { maybeForceBuilderInitialization(); } private Builder( BuilderParent parent) { super(parent); maybeForceBuilderInitialization(); } private void maybeForceBuilderInitialization() { if (com.google.protobuf.GeneratedMessageV3 .alwaysUseFieldBuilders) { } } @Override public Builder clear() { super.clear(); id_ = 0; name_ = ""; return this; } @Override public com.google.protobuf.Descriptors.Descriptor getDescriptorForType() { return StudentPOJO.internal_static_Student_descriptor; } @Override public Student getDefaultInstanceForType() { return Student.getDefaultInstance(); } @Override public Student build() { Student result = buildPartial(); if (!result.isInitialized()) { throw newUninitializedMessageException(result); } return result; } @Override public Student buildPartial() { Student result = new Student(this); result.id_ = id_; result.name_ = name_; onBuilt(); return result; } @Override public Builder clone() { return (Builder) super.clone(); } @Override public Builder setField( com.google.protobuf.Descriptors.FieldDescriptor field, Object value) { return (Builder) super.setField(field, value); } @Override public Builder clearField( com.google.protobuf.Descriptors.FieldDescriptor field) { return (Builder) super.clearField(field); } @Override public Builder clearOneof( com.google.protobuf.Descriptors.OneofDescriptor oneof) { return (Builder) super.clearOneof(oneof); } @Override public Builder setRepeatedField( com.google.protobuf.Descriptors.FieldDescriptor field, int index, Object value) { return (Builder) super.setRepeatedField(field, index, value); } @Override public Builder addRepeatedField( com.google.protobuf.Descriptors.FieldDescriptor field, Object value) { return (Builder) super.addRepeatedField(field, value); } @Override public Builder mergeFrom(com.google.protobuf.Message other) { if (other instanceof Student) { return mergeFrom((Student)other); } else { super.mergeFrom(other); return this; } } public Builder mergeFrom(Student other) { if (other == Student.getDefaultInstance()) return this; if (other.getId() != 0) { setId(other.getId()); } if (!other.getName().isEmpty()) { name_ = other.name_; onChanged(); } this.mergeUnknownFields(other.unknownFields); onChanged(); return this; } @Override public final boolean isInitialized() { return true; } @Override public Builder mergeFrom( com.google.protobuf.CodedInputStream input, com.google.protobuf.ExtensionRegistryLite extensionRegistry) throws java.io.IOException { Student parsedMessage = null; try { parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry); } catch (com.google.protobuf.InvalidProtocolBufferException e) { parsedMessage = (Student) e.getUnfinishedMessage(); throw e.unwrapIOException(); } finally { if (parsedMessage != null) { mergeFrom(parsedMessage); } } return this; } private int id_ ; /** *
       *student类中有一个属性 名字为id 类型为int32(protibuf类型) 1表示属性序号
       * 
* * int32 id = 1; */
public int getId() { return id_; } /** *
       *student类中有一个属性 名字为id 类型为int32(protibuf类型) 1表示属性序号
       * 
* * int32 id = 1; */
public Builder setId(int value) { id_ = value; onChanged(); return this; } /** *
       *student类中有一个属性 名字为id 类型为int32(protibuf类型) 1表示属性序号
       * 
* * int32 id = 1; */
public Builder clearId() { id_ = 0; onChanged(); return this; } private Object name_ = ""; /** * string name = 2; */ public String getName() { Object ref = name_; if (!(ref instanceof String)) { com.google.protobuf.ByteString bs = (com.google.protobuf.ByteString) ref; String s = bs.toStringUtf8(); name_ = s; return s; } else { return (String) ref; } } /** * string name = 2; */ public com.google.protobuf.ByteString getNameBytes() { Object ref = name_; if (ref instanceof String) { com.google.protobuf.ByteString b = com.google.protobuf.ByteString.copyFromUtf8( (String) ref); name_ = b; return b; } else { return (com.google.protobuf.ByteString) ref; } } /** * string name = 2; */ public Builder setName( String value) { if (value == null) { throw new NullPointerException(); } name_ = value; onChanged(); return this; } /** * string name = 2; */ public Builder clearName() { name_ = getDefaultInstance().getName(); onChanged(); return this; } /** * string name = 2; */ public Builder setNameBytes( com.google.protobuf.ByteString value) { if (value == null) { throw new NullPointerException(); } checkByteStringIsUtf8(value); name_ = value; onChanged(); return this; } @Override public final Builder setUnknownFields( final com.google.protobuf.UnknownFieldSet unknownFields) { return super.setUnknownFieldsProto3(unknownFields); } @Override public final Builder mergeUnknownFields( final com.google.protobuf.UnknownFieldSet unknownFields) { return super.mergeUnknownFields(unknownFields); } // @@protoc_insertion_point(builder_scope:Student) } // @@protoc_insertion_point(class_scope:Student) private static final Student DEFAULT_INSTANCE; static { DEFAULT_INSTANCE = new Student(); } public static Student getDefaultInstance() { return DEFAULT_INSTANCE; } private static final com.google.protobuf.Parser<Student> PARSER = new com.google.protobuf.AbstractParser<Student>() { @Override public Student parsePartialFrom( com.google.protobuf.CodedInputStream input, com.google.protobuf.ExtensionRegistryLite extensionRegistry) throws com.google.protobuf.InvalidProtocolBufferException { return new Student(input, extensionRegistry); } }; public static com.google.protobuf.Parser<Student> parser() { return PARSER; } @Override public com.google.protobuf.Parser<Student> getParserForType() { return PARSER; } @Override public Student getDefaultInstanceForType() { return DEFAULT_INSTANCE; } } private static final com.google.protobuf.Descriptors.Descriptor internal_static_Student_descriptor; private static final com.google.protobuf.GeneratedMessageV3.FieldAccessorTable internal_static_Student_fieldAccessorTable; public static com.google.protobuf.Descriptors.FileDescriptor getDescriptor() { return descriptor; } private static com.google.protobuf.Descriptors.FileDescriptor descriptor; static { String[] descriptorData = { "\n\rStudent.proto\"#\n\007Student\022\n\n\002id\030\001 \001(\005\022\014" + "\n\004name\030\002 \001(\tB\rB\013StudentPOJOb\006proto3" }; com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner assigner = new com.google.protobuf.Descriptors.FileDescriptor. InternalDescriptorAssigner() { public com.google.protobuf.ExtensionRegistry assignDescriptors( com.google.protobuf.Descriptors.FileDescriptor root) { descriptor = root; return null; } }; com.google.protobuf.Descriptors.FileDescriptor .internalBuildGeneratedFileFrom(descriptorData, new com.google.protobuf.Descriptors.FileDescriptor[] { }, assigner); internal_static_Student_descriptor = getDescriptor().getMessageTypes().get(0); internal_static_Student_fieldAccessorTable = new com.google.protobuf.GeneratedMessageV3.FieldAccessorTable( internal_static_Student_descriptor, new String[] { "Id", "Name", }); } // @@protoc_insertion_point(outer_class_scope) }

将序列化后的Java类放到项目中即可使用

示例:基于ProtoBuf实现简单的通讯

  1. 客户端发送一个Student对象到服务器
  2. 服务器端接收到Student对象 并显示信息
  3. 使用ProtoBuf编解码

服务器端

public class NettyProtoBufServer {
    public static void main(String[] args) {

        EventLoopGroup bossGroup = new NioEventLoopGroup(1);
        EventLoopGroup workerGroup = new NioEventLoopGroup();

        try {

            ServerBootstrap serverBootstrap = new ServerBootstrap();
            serverBootstrap.group(bossGroup, workerGroup)
                    .channel(NioServerSocketChannel.class)
                    .option(ChannelOption.SO_BACKLOG, 128)
                    .childHandler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        protected void initChannel(SocketChannel ch) throws Exception {

                            ChannelPipeline pipeline = ch.pipeline();

                            //对哪种类型进行解码
                            pipeline.addLast("decoder", new ProtobufDecoder(StudentPOJO.Student.getDefaultInstance()));

                            pipeline.addLast(new NettyProtoBufHandler());


                        }
                    });

            ChannelFuture channelFuture = serverBootstrap.bind(8899).sync();
            channelFuture.channel().closeFuture().sync();

        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            bossGroup.shutdownGracefully();
            workerGroup.shutdownGracefully();
        }


    }
}

//handler
public class NettyProtoBufHandler extends ChannelInboundHandlerAdapter {

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        StudentPOJO.Student student = (StudentPOJO.Student) msg;
        System.out.println("from client:" + student.getId() + "====>" + student.getName());
    }

    @Override
    public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
        ctx.writeAndFlush(Unpooled.copiedBuffer("msg from server", CharsetUtil.UTF_8));
    }
}

客户端代码

public class NettyProtoBufClient {
    public static void main(String[] args) {

        EventLoopGroup eventLoopGroup = new NioEventLoopGroup();

        try {

            Bootstrap bootstrap = new Bootstrap();
            bootstrap.group(eventLoopGroup)
                    .channel(NioSocketChannel.class)
                    .handler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        protected void initChannel(SocketChannel ch) throws Exception {
                            ChannelPipeline pipeline = ch.pipeline();
                            //编码器
                            pipeline.addLast("encoder", new ProtobufEncoder());
                            pipeline.addLast(new NettyProtoBufClientHandler());
                        }
                    });

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

        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            eventLoopGroup.shutdownGracefully();
        }

    }
}

//handler
public class NettyProtoBufClientHandler extends ChannelInboundHandlerAdapter {


    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        StudentPOJO.Student student = StudentPOJO.Student.newBuilder().setId(1).setName("abc").build();
        ctx.writeAndFlush(student);
    }

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {

        ByteBuf buf= (ByteBuf) msg;
        System.out.println(buf.toString(CharsetUtil.UTF_8));


    }

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

注意:这里在客户端和服务器端加上了与ProtoBuf有关的编解码器

上面的例子服务器端只会生成一种特定类型的对象,如果服务器端想要根据业务获取不同类型的对象可参见下面的例子

syntax = "proto3";

option java_outer_classname = "RolePOJO";
option java_package = "com.wojiushiwo.protobuf.multi";

message Role {
    //declare enum
    enum DataType {
        Student = 0;
        Worker = 1;
    }
    //first field
    DataType dataType = 1;
    //can select one of declared field
    oneof dataBody {
        Student student = 2;
        Worker worker = 3;
    }

}

message Student {
    int32 id = 1;
    string name = 2;
}

message Worker {
    string name = 1;
    int32 age = 2;
}

服务端代码

public class NettyMultiProtoBufTypeServer {

    public static void main(String[] args) {
        EventLoopGroup bossGroup = new NioEventLoopGroup(1);
        EventLoopGroup workerGroup = new NioEventLoopGroup();

        try {

            ServerBootstrap serverBootstrap = new ServerBootstrap();
            serverBootstrap.group(bossGroup, workerGroup)
                    .channel(NioServerSocketChannel.class)
                    .option(ChannelOption.SO_BACKLOG, 128)
                    .childHandler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        protected void initChannel(SocketChannel ch) throws Exception {
                            ChannelPipeline pipeline = ch.pipeline();

                            // 这里服务器端添加的是针对protoBuf的解码器
                            pipeline.addLast("decoder", new ProtobufDecoder(RolePOJO.Role.getDefaultInstance()));
                            pipeline.addLast(new MultiProtoBufServerHandler());
                        }
                    });

            ChannelFuture channelFuture = serverBootstrap.bind(8900).sync();
            channelFuture.channel().closeFuture().sync();

        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            bossGroup.shutdownGracefully();
            workerGroup.shutdownGracefully();
        }
    }

}

//handler
public class MultiProtoBufServerHandler extends SimpleChannelInboundHandler<RolePOJO.Role> {
    @Override
    protected void channelRead0(ChannelHandlerContext ctx, RolePOJO.Role msg) throws Exception {

        RolePOJO.Role.DataType dataType = msg.getDataType();
        if (Objects.equals(dataType, RolePOJO.Role.DataType.Student)) {

            RolePOJO.Student student = msg.getStudent();
            System.out.println("获取到客户端发送的信息:" + student.getId() + "," + student.getName());

        } else if (Objects.equals(dataType, RolePOJO.Role.DataType.Worker)) {
            RolePOJO.Worker worker = msg.getWorker();
            System.out.println("获取到客户端发送的信息:" + worker.getAge() + "," + worker.getName());
        } else {
            System.out.println("获取到客户端发送的信息");
        }

    }

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

客户端代码

package com.wojiushiwo.protobuf.multi;

import io.netty.bootstrap.Bootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.protobuf.ProtobufEncoder;

/**
 * Created by myk
 * 2020/1/29 下午5:40
 */
public class NettyMultiProtoBufTypeClient {

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

        try {
            Bootstrap bootstrap = new Bootstrap();
            bootstrap.group(eventLoopGroup)
                    .channel(NioSocketChannel.class)
                    .handler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        protected void initChannel(SocketChannel ch) throws Exception {
                            ChannelPipeline pipeline = ch.pipeline();
                            pipeline.addLast(new ProtobufEncoder());
                            pipeline.addLast(new MultiProtoBufClientHandler());
                        }
                    });

            ChannelFuture channelFuture = bootstrap.connect("127.0.0.1", 8900).sync();
            channelFuture.channel().closeFuture().sync();

        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            eventLoopGroup.shutdownGracefully();
        }
    }
}

//handler
package com.wojiushiwo.protobuf.multi;

import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;

/**
 * Created by myk
 * 2020/1/29 下午5:41
 */
public class MultiProtoBufClientHandler extends ChannelInboundHandlerAdapter {

    public static void main(String[] args) {
        System.out.println((int) (Math.random() * 10));
    }

    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        int randomNum = (int) (Math.random() * 10);
        RolePOJO.Role role;
        if (randomNum % 2 == 0) {
            RolePOJO.Student student = RolePOJO.Student.newBuilder().setId(1).setName("student").build();
            role = RolePOJO.Role.newBuilder().setDataType(RolePOJO.Role.DataType.Student)
                    .setStudent(student).build();

        } else {
            RolePOJO.Worker worker = RolePOJO.Worker.newBuilder().setAge(20).setName("worker").build();
            role = RolePOJO.Role.newBuilder().setDataType(RolePOJO.Role.DataType.Worker)
                    .setWorker(worker).build();

        }
        ctx.writeAndFlush(role);
    }

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

上面使用到了ProtoBuf中的语法enum,如果想查看ProtoBuf语法的其他用法可参见ProtoBuf语法

你可能感兴趣的:(Netty学习笔记)