【六】Netty Google Protobuf 编解码

Google Protobuf 介绍

Google 的 Protobuf 在业界非常流行,很多商业项目选择Protobuf 作为编解码框架,Protobuf的优点如下:
(1)在谷歌内部长期使用,产品成熟度高;
(2)跨语言,支持多种语言,包括C++,Java和Python
(3)编码后的消息很小,更加有利于存储和传输
(4)编解码的性能非常高
(5)支持不同协议版本的向前兼容
(6)支持定义可选和必选字段

Protobuf 的入门

Protobuf 是一个灵活,高效,结构化的数据序列化框架,相比于XML等传统的序列化工具,它更小,更快,更简单。Protobuf 支持数据结构化一次可以到处使用,甚至跨语言使用,通过代码生成工具可以自动生成不同语言版本的源代码,甚至可以在使用不同版本的数据结构进程间进行数据传递,实现数据结构的向前兼容。

Protobuf 开发环境搭建

Protobuf 下载

Protobuf的2.5.0 版本下载地址:
1.在官网上面,找到 2.5.0 版本下载。
https://github.com/protocolbuffers/protobuf/releases?page=12
2.在csdn 界面下载
https://download.csdn.net/download/echohuangshihuxue/87374990
下载后解压如图:
在这里插入图片描述

创建.proto文件

我们基于 第五节(https://blog.csdn.net/echohuangshihuxue/article/details/128603624)
的 POJO SubscribeReq(订购请求实体)和SubscribeResp(订购应答实体) 来生成.proto文件。

第五节的 对应实体(SubscribeReq,SubscribeResp )
public class SubscribeReq implements Serializable {
    private static final long serialVersionUID=1L;
    //订购编号
    private int subReqID;
    //用户名
    private String userName;
    //订购的产品名称
    private String productName;
    //订购者的电话号码
    private String phoneNumber;
    //订购者的家庭地址
    private String address;


    public int getSubReqID() {
        return subReqID;
    }

    public void setSubReqID(int subReqID) {
        this.subReqID = subReqID;
    }

    public String getUserName() {
        return userName;
    }

    public void setUserName(String userName) {
        this.userName = userName;
    }

    public String getProductName() {
        return productName;
    }

    public void setProductName(String productName) {
        this.productName = productName;
    }

    public String getPhoneNumber() {
        return phoneNumber;
    }

    public void setPhoneNumber(String phoneNumber) {
        this.phoneNumber = phoneNumber;
    }

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }

    public String toString(){
        return "SubscribeReq [ subReqID = "+subReqID+" , userName = " +
                ""+userName+" , productName = "+productName+" ," +
                " phoneNumber = "+phoneNumber+" , address = "+address+" ]";
    }
}

public class SubscribeResp implements Serializable {
    private static final long serialVersionUID=1L;
    //订购编号
    private int subReqID;
    //订购结果 0 表示成功
    private int respCode;
    //可选的详细描述信息
    private String desc;

    public int getSubReqID() {
        return subReqID;
    }

    public void setSubReqID(int subReqID) {
        this.subReqID = subReqID;
    }

    public int getRespCode() {
        return respCode;
    }

    public void setRespCode(int respCode) {
        this.respCode = respCode;
    }

    public String getDesc() {
        return desc;
    }

    public void setDesc(String desc) {
        this.desc = desc;
    }

    public String toString(){
        return "SubscribeResp [ subReqID = "+subReqID+" " +
                ", respCode = "+respCode+" , desc = "+desc+" ]";
    }
}

SubscribeReq.proto 文件
//定义协议类型
syntax="proto2";
//生成的Java文件的包名
package echo.cn;
//生成的Java文件的包名
option java_package ="echo.cn";
option java_multiple_files=true;
//生成的java 的类名
option java_outer_classname="SubscribeReqProto";


message SubscribeReq{
  required int32 subReqID = 1;
  required string userName=2;
  required string productName=3;
  required string phoneNumber=4;
  required string address=5;
}
SubscribeResp.proto
//协议类型
syntax="proto2";
package echo.cn;

option java_package ="echo.cn";
option java_multiple_files=true;
//生成的Java 文件的类名
option java_outer_classname="SubscribeRespProto";

message SubscribeResp{
  required int32 subReqID = 1;
  required int32 respCode=2;
  required string desc=3;
}

利用命令生成对应的java文件

将.proto文件和protoc.exe 放入同一个文件夹。然后在这个目录打开powerShell

在这里插入图片描述

然后在 当前目录的上级目录的src 目录下的echo.cn 目录下面就会生成对应的java文件。

在这里插入图片描述

测试下生成的java文件

写个简单的demo 验证下:

测试代码:
public class TestSubscribeReqProto {
    private static byte[] encode(SubscribeReq req){
        //SubscribeReq 能直接获取byte[],非常方便
        return req.toByteArray();
    }

    private static SubscribeReq decode(byte[]body) throws InvalidProtocolBufferException {
        //将二进制byte数组解码还原为原始的对象
        return SubscribeReq.parseFrom(body);
    }

    private static SubscribeReq createSubscribeReq(){
        //通过构建起对SubscribeReq的属性进行设置
        SubscribeReq.Builder builder=SubscribeReq.newBuilder();
        builder.setSubReqID(1);
        builder.setUserName("echo");
        builder.setProductName("netty learning protobuf");
        builder.setPhoneNumber("17748694444");
        builder.setAddress("shenzhen");
        return builder.build();
    }

    public static void main(String[] args) throws InvalidProtocolBufferException {
        SubscribeReq req=createSubscribeReq();
        System.out.println("Before encode(解码前) : "+req.toString());
        //先编码然后再解码,得到的对象和原始对象 equals比较。
        // 先编码再解码,模拟 不同进程 的工作,发送方 编码, 接收方解码。然后 得到的对象是否相等。
        // 如果相等,说明 protobuf 支持编解码
        SubscribeReq req1=decode(encode(req));
        System.out.println("After decode : "+req1.toString());
        System.out.println("Assert equal : --> "+req1.equals(req));
    }
}
运行效果截图:

在这里插入图片描述
好了,说明我们生成的java 文件是ok 的。接下来我们来依据protobuf 来实现编码解码的功能。

Protobuf 版本的订购程序

流程图

在这里插入图片描述

maven jar 依赖

          <!-- protobuf -->
        <dependency>
            <groupId>com.google.protobuf</groupId>
            <artifactId>protobuf-java</artifactId>
            <version>2.5.0</version>
        </dependency>
        <dependency>
            <groupId>com.googlecode.protobuf-java-format</groupId>
            <artifactId>protobuf-java-format</artifactId>
            <version>1.2</version>
        </dependency>

代码展示

服务端启动类 SubscribeReqServer

public class SubscribeReqServer {
    public void bind(int port){
        //配置服务端的NIO线程组
        EventLoopGroup parentGroup=new NioEventLoopGroup();
        EventLoopGroup childGroup=new NioEventLoopGroup();
        try {
            ServerBootstrap bootstrap=new ServerBootstrap();
            bootstrap.group(parentGroup,childGroup)
                    .channel(NioServerSocketChannel.class)
                    .option(ChannelOption.SO_BACKLOG,100)
                    .handler(new LoggingHandler(LogLevel.INFO))
                    .childHandler(new ChannelInitializer<SocketChannel>() {
                        protected void initChannel(SocketChannel socketChannel) throws Exception {
                            // ProtobufVarint32FrameDecoder 主要用于半包处理
                         socketChannel.pipeline().addLast(
                                 new ProtobufVarint32FrameDecoder()
                         );
                         // ProtobufDecoder 的参数是 SubscribeReq,实际上就是要告诉
                            //ProtobufDecoder 需要解码的目标类是什么,否则仅仅从字节数组中是无法
                            //判断出需要解码的目标类型信息的。
                         socketChannel.pipeline()
                                         .addLast(new ProtobufDecoder(SubscribeReq.getDefaultInstance()));
                         socketChannel.pipeline()
                                         .addLast(new ProtobufVarint32LengthFieldPrepender());
                         socketChannel.pipeline()
                                         .addLast(new ProtobufEncoder());
                            socketChannel.pipeline()
                                    .addLast(new SubscribeServerHandler());
                        }
                    });
            //绑定端口,同步等待成功
            ChannelFuture future=bootstrap.bind(port).sync();
            System.out.println("netty server is started");
           // 等待服务器监听端口关闭
            future.channel().closeFuture().sync();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }finally {
            //优雅退出,释放线程池资源
            parentGroup.shutdownGracefully();
            childGroup.shutdownGracefully();
        }
    }

    public static void main(String[] args) {
        new SubscribeReqServer().bind(8080);
    }
}

服务端业务处理类 SubscribeServerHandler

public class SubscribeServerHandler extends ChannelHandlerAdapter {

    public void channelRead(ChannelHandlerContext context, Object obj){
        SubscribeReq subscribeReq=(SubscribeReq)obj;
        //对合法性进行交易,当前只校验userName属性。如果符合,将信息发送给客户端
        if ("echo".equals(subscribeReq.getUserName())){
            System.out.println("Service accept client subscribe req : "+subscribeReq);
            context.writeAndFlush(resp(subscribeReq.getSubReqID()));
        }
    }

    private SubscribeResp resp(int subId){
        //SubscribeResp subscribeResp=SubscribeResp.newBuilder().build();
        SubscribeResp.Builder builder=SubscribeResp.newBuilder();
        builder.setSubReqID(subId);
        builder.setRespCode(0);
        builder.setDesc("Netty learning is doing,please go on .");
        SubscribeResp subscribeResp=builder.build();
        System.out.println(subscribeResp);
        return subscribeResp;
    }

   public void exceptionCaught(ChannelHandlerContext context,Throwable throwable){
        throwable.printStackTrace();
        context.close();
    }


}

客户端启动类 SubscribeClient

public class SubscribeClient {

    private void connect(String host, int port) {
        EventLoopGroup workGroup = new NioEventLoopGroup();
        try {
            Bootstrap bootstrap = new Bootstrap();
            bootstrap.group(workGroup)
                    .option(ChannelOption.TCP_NODELAY, true)
                    .channel(NioSocketChannel.class)
                    .handler(new ChannelInitializer<SocketChannel>() {
                        protected void initChannel(SocketChannel socketChannel) throws Exception {
                            socketChannel.pipeline()
                                            .addLast(new ProtobufVarint32FrameDecoder());
                            socketChannel.pipeline()
                                            .addLast(new ProtobufDecoder(SubscribeResp.getDefaultInstance()));
                            socketChannel.pipeline()
                                            .addLast(new ProtobufVarint32LengthFieldPrepender());
                            socketChannel.pipeline()
                                            .addLast(new ProtobufEncoder());
                            socketChannel.pipeline().addLast(new SubscribeClientHandler());

                        }
                    });
            ChannelFuture future=bootstrap.connect(host,port).sync();
            System.out.println("the netty client is started,and connected server");
            future.channel().closeFuture().sync();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }finally {
            //优雅退出
            workGroup.shutdownGracefully();
        }
    }

    public static void main(String[] args) {
        new SubscribeClient().connect("127.0.00.1",8080);
    }
}

客户端业务处理类 SubscribeClientHandler

public class SubscribeClientHandler extends ChannelHandlerAdapter {

    //tcp 链接成功后,就给服务端 循环发送10条信息
    public void channelActive(ChannelHandlerContext context){
        for (int i=0;i<10;i++){
            context.write(subReq(i));
        }
        context.flush();
    }

    private SubscribeReq subReq(int i){
        SubscribeReq.Builder builder=SubscribeReq.newBuilder();
        builder.setSubReqID(i);
        builder.setAddress("shen zhen xixiang dadao");
        builder.setPhoneNumber("174868xxxx");
        builder.setProductName("Netty learning ");
        builder.setUserName("echo");
        return  builder.build();
    }

    /**
     * 由于对象解码器已经对 SubscribeResp 请求消息 进行了自动解码,
     * 因此
     * @param context
     * @param obj
     */
    public void channelRead(ChannelHandlerContext context,Object obj){
       // System.out.println("hello ni hao ");
        System.out.println("Receive server response : "+obj);
    }

    public void channelReadComplete(ChannelHandlerContext context){
        context.flush();
    }



}

还有之前通过protoc.exe 生成的java 文件

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

package echo.cn;

/**
 * Protobuf type {@code echo.cn.SubscribeReq}
 */
public  final class SubscribeReq extends
    com.google.protobuf.GeneratedMessage
    implements SubscribeReqOrBuilder {
  // Use SubscribeReq.newBuilder() to construct.
  private SubscribeReq(com.google.protobuf.GeneratedMessage.Builder<?> builder) {
    super(builder);
    this.unknownFields = builder.getUnknownFields();
  }
  private SubscribeReq(boolean noInit) { this.unknownFields = com.google.protobuf.UnknownFieldSet.getDefaultInstance(); }

  private static final SubscribeReq defaultInstance;
  public static SubscribeReq getDefaultInstance() {
    return defaultInstance;
  }

  public SubscribeReq getDefaultInstanceForType() {
    return defaultInstance;
  }

  private final com.google.protobuf.UnknownFieldSet unknownFields;
  @Override
  public final com.google.protobuf.UnknownFieldSet
      getUnknownFields() {
    return this.unknownFields;
  }
  private SubscribeReq(
      com.google.protobuf.CodedInputStream input,
      com.google.protobuf.ExtensionRegistryLite extensionRegistry)
      throws com.google.protobuf.InvalidProtocolBufferException {
    initFields();
    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;
          default: {
            if (!parseUnknownField(input, unknownFields,
                                   extensionRegistry, tag)) {
              done = true;
            }
            break;
          }
          case 8: {
            bitField0_ |= 0x00000001;
            subReqID_ = input.readInt32();
            break;
          }
          case 18: {
            bitField0_ |= 0x00000002;
            userName_ = input.readBytes();
            break;
          }
          case 26: {
            bitField0_ |= 0x00000004;
            productName_ = input.readBytes();
            break;
          }
          case 34: {
            bitField0_ |= 0x00000008;
            phoneNumber_ = input.readBytes();
            break;
          }
          case 42: {
            bitField0_ |= 0x00000010;
            address_ = input.readBytes();
            break;
          }
        }
      }
    } catch (com.google.protobuf.InvalidProtocolBufferException e) {
      throw e.setUnfinishedMessage(this);
    } catch (java.io.IOException e) {
      throw new com.google.protobuf.InvalidProtocolBufferException(
          e.getMessage()).setUnfinishedMessage(this);
    } finally {
      this.unknownFields = unknownFields.build();
      makeExtensionsImmutable();
    }
  }
  public static final com.google.protobuf.Descriptors.Descriptor
      getDescriptor() {
    return SubscribeReqProto.internal_static_echo_cn_SubscribeReq_descriptor;
  }

  protected FieldAccessorTable
      internalGetFieldAccessorTable() {
    return SubscribeReqProto.internal_static_echo_cn_SubscribeReq_fieldAccessorTable
        .ensureFieldAccessorsInitialized(
            SubscribeReq.class, Builder.class);
  }

  public static com.google.protobuf.Parser<SubscribeReq> PARSER =
      new com.google.protobuf.AbstractParser<SubscribeReq>() {
    public SubscribeReq parsePartialFrom(
        com.google.protobuf.CodedInputStream input,
        com.google.protobuf.ExtensionRegistryLite extensionRegistry)
        throws com.google.protobuf.InvalidProtocolBufferException {
      return new SubscribeReq(input, extensionRegistry);
    }
  };

  @Override
  public com.google.protobuf.Parser<SubscribeReq> getParserForType() {
    return PARSER;
  }

  private int bitField0_;
  // required int32 subReqID = 1;
  public static final int SUBREQID_FIELD_NUMBER = 1;
  private int subReqID_;
  /**
   * <code>required int32 subReqID = 1;</code>
   */
  public boolean hasSubReqID() {
    return ((bitField0_ & 0x00000001) == 0x00000001);
  }
  /**
   * <code>required int32 subReqID = 1;</code>
   */
  public int getSubReqID() {
    return subReqID_;
  }

  // required string userName = 2;
  public static final int USERNAME_FIELD_NUMBER = 2;
  private Object userName_;
  /**
   * <code>required string userName = 2;</code>
   */
  public boolean hasUserName() {
    return ((bitField0_ & 0x00000002) == 0x00000002);
  }
  /**
   * <code>required string userName = 2;</code>
   */
  public String getUserName() {
    Object ref = userName_;
    if (ref instanceof String) {
      return (String) ref;
    } else {
      com.google.protobuf.ByteString bs = 
          (com.google.protobuf.ByteString) ref;
      String s = bs.toStringUtf8();
      if (bs.isValidUtf8()) {
        userName_ = s;
      }
      return s;
    }
  }
  /**
   * <code>required string userName = 2;</code>
   */
  public com.google.protobuf.ByteString
      getUserNameBytes() {
    Object ref = userName_;
    if (ref instanceof String) {
      com.google.protobuf.ByteString b = 
          com.google.protobuf.ByteString.copyFromUtf8(
              (String) ref);
      userName_ = b;
      return b;
    } else {
      return (com.google.protobuf.ByteString) ref;
    }
  }

  // required string productName = 3;
  public static final int PRODUCTNAME_FIELD_NUMBER = 3;
  private Object productName_;
  /**
   * <code>required string productName = 3;</code>
   */
  public boolean hasProductName() {
    return ((bitField0_ & 0x00000004) == 0x00000004);
  }
  /**
   * <code>required string productName = 3;</code>
   */
  public String getProductName() {
    Object ref = productName_;
    if (ref instanceof String) {
      return (String) ref;
    } else {
      com.google.protobuf.ByteString bs = 
          (com.google.protobuf.ByteString) ref;
      String s = bs.toStringUtf8();
      if (bs.isValidUtf8()) {
        productName_ = s;
      }
      return s;
    }
  }
  /**
   * <code>required string productName = 3;</code>
   */
  public com.google.protobuf.ByteString
      getProductNameBytes() {
    Object ref = productName_;
    if (ref instanceof String) {
      com.google.protobuf.ByteString b = 
          com.google.protobuf.ByteString.copyFromUtf8(
              (String) ref);
      productName_ = b;
      return b;
    } else {
      return (com.google.protobuf.ByteString) ref;
    }
  }

  // required string phoneNumber = 4;
  public static final int PHONENUMBER_FIELD_NUMBER = 4;
  private Object phoneNumber_;
  /**
   * <code>required string phoneNumber = 4;</code>
   */
  public boolean hasPhoneNumber() {
    return ((bitField0_ & 0x00000008) == 0x00000008);
  }
  /**
   * <code>required string phoneNumber = 4;</code>
   */
  public String getPhoneNumber() {
    Object ref = phoneNumber_;
    if (ref instanceof String) {
      return (String) ref;
    } else {
      com.google.protobuf.ByteString bs = 
          (com.google.protobuf.ByteString) ref;
      String s = bs.toStringUtf8();
      if (bs.isValidUtf8()) {
        phoneNumber_ = s;
      }
      return s;
    }
  }
  /**
   * <code>required string phoneNumber = 4;</code>
   */
  public com.google.protobuf.ByteString
      getPhoneNumberBytes() {
    Object ref = phoneNumber_;
    if (ref instanceof String) {
      com.google.protobuf.ByteString b = 
          com.google.protobuf.ByteString.copyFromUtf8(
              (String) ref);
      phoneNumber_ = b;
      return b;
    } else {
      return (com.google.protobuf.ByteString) ref;
    }
  }

  // required string address = 5;
  public static final int ADDRESS_FIELD_NUMBER = 5;
  private Object address_;
  /**
   * <code>required string address = 5;</code>
   */
  public boolean hasAddress() {
    return ((bitField0_ & 0x00000010) == 0x00000010);
  }
  /**
   * <code>required string address = 5;</code>
   */
  public String getAddress() {
    Object ref = address_;
    if (ref instanceof String) {
      return (String) ref;
    } else {
      com.google.protobuf.ByteString bs = 
          (com.google.protobuf.ByteString) ref;
      String s = bs.toStringUtf8();
      if (bs.isValidUtf8()) {
        address_ = s;
      }
      return s;
    }
  }
  /**
   * <code>required string address = 5;</code>
   */
  public com.google.protobuf.ByteString
      getAddressBytes() {
    Object ref = address_;
    if (ref instanceof String) {
      com.google.protobuf.ByteString b = 
          com.google.protobuf.ByteString.copyFromUtf8(
              (String) ref);
      address_ = b;
      return b;
    } else {
      return (com.google.protobuf.ByteString) ref;
    }
  }

  private void initFields() {
    subReqID_ = 0;
    userName_ = "";
    productName_ = "";
    phoneNumber_ = "";
    address_ = "";
  }
  private byte memoizedIsInitialized = -1;
  public final boolean isInitialized() {
    byte isInitialized = memoizedIsInitialized;
    if (isInitialized != -1) return isInitialized == 1;

    if (!hasSubReqID()) {
      memoizedIsInitialized = 0;
      return false;
    }
    if (!hasUserName()) {
      memoizedIsInitialized = 0;
      return false;
    }
    if (!hasProductName()) {
      memoizedIsInitialized = 0;
      return false;
    }
    if (!hasPhoneNumber()) {
      memoizedIsInitialized = 0;
      return false;
    }
    if (!hasAddress()) {
      memoizedIsInitialized = 0;
      return false;
    }
    memoizedIsInitialized = 1;
    return true;
  }

  public void writeTo(com.google.protobuf.CodedOutputStream output)
                      throws java.io.IOException {
    getSerializedSize();
    if (((bitField0_ & 0x00000001) == 0x00000001)) {
      output.writeInt32(1, subReqID_);
    }
    if (((bitField0_ & 0x00000002) == 0x00000002)) {
      output.writeBytes(2, getUserNameBytes());
    }
    if (((bitField0_ & 0x00000004) == 0x00000004)) {
      output.writeBytes(3, getProductNameBytes());
    }
    if (((bitField0_ & 0x00000008) == 0x00000008)) {
      output.writeBytes(4, getPhoneNumberBytes());
    }
    if (((bitField0_ & 0x00000010) == 0x00000010)) {
      output.writeBytes(5, getAddressBytes());
    }
    getUnknownFields().writeTo(output);
  }

  private int memoizedSerializedSize = -1;
  public int getSerializedSize() {
    int size = memoizedSerializedSize;
    if (size != -1) return size;

    size = 0;
    if (((bitField0_ & 0x00000001) == 0x00000001)) {
      size += com.google.protobuf.CodedOutputStream
        .computeInt32Size(1, subReqID_);
    }
    if (((bitField0_ & 0x00000002) == 0x00000002)) {
      size += com.google.protobuf.CodedOutputStream
        .computeBytesSize(2, getUserNameBytes());
    }
    if (((bitField0_ & 0x00000004) == 0x00000004)) {
      size += com.google.protobuf.CodedOutputStream
        .computeBytesSize(3, getProductNameBytes());
    }
    if (((bitField0_ & 0x00000008) == 0x00000008)) {
      size += com.google.protobuf.CodedOutputStream
        .computeBytesSize(4, getPhoneNumberBytes());
    }
    if (((bitField0_ & 0x00000010) == 0x00000010)) {
      size += com.google.protobuf.CodedOutputStream
        .computeBytesSize(5, getAddressBytes());
    }
    size += getUnknownFields().getSerializedSize();
    memoizedSerializedSize = size;
    return size;
  }

  private static final long serialVersionUID = 0L;
  @Override
  protected Object writeReplace()
      throws java.io.ObjectStreamException {
    return super.writeReplace();
  }

  public static SubscribeReq parseFrom(
      com.google.protobuf.ByteString data)
      throws com.google.protobuf.InvalidProtocolBufferException {
    return PARSER.parseFrom(data);
  }
  public static SubscribeReq parseFrom(
      com.google.protobuf.ByteString data,
      com.google.protobuf.ExtensionRegistryLite extensionRegistry)
      throws com.google.protobuf.InvalidProtocolBufferException {
    return PARSER.parseFrom(data, extensionRegistry);
  }
  public static SubscribeReq parseFrom(byte[] data)
      throws com.google.protobuf.InvalidProtocolBufferException {
    return PARSER.parseFrom(data);
  }
  public static SubscribeReq parseFrom(
      byte[] data,
      com.google.protobuf.ExtensionRegistryLite extensionRegistry)
      throws com.google.protobuf.InvalidProtocolBufferException {
    return PARSER.parseFrom(data, extensionRegistry);
  }
  public static SubscribeReq parseFrom(java.io.InputStream input)
      throws java.io.IOException {
    return PARSER.parseFrom(input);
  }
  public static SubscribeReq parseFrom(
      java.io.InputStream input,
      com.google.protobuf.ExtensionRegistryLite extensionRegistry)
      throws java.io.IOException {
    return PARSER.parseFrom(input, extensionRegistry);
  }
  public static SubscribeReq parseDelimitedFrom(java.io.InputStream input)
      throws java.io.IOException {
    return PARSER.parseDelimitedFrom(input);
  }
  public static SubscribeReq parseDelimitedFrom(
      java.io.InputStream input,
      com.google.protobuf.ExtensionRegistryLite extensionRegistry)
      throws java.io.IOException {
    return PARSER.parseDelimitedFrom(input, extensionRegistry);
  }
  public static SubscribeReq parseFrom(
      com.google.protobuf.CodedInputStream input)
      throws java.io.IOException {
    return PARSER.parseFrom(input);
  }
  public static SubscribeReq parseFrom(
      com.google.protobuf.CodedInputStream input,
      com.google.protobuf.ExtensionRegistryLite extensionRegistry)
      throws java.io.IOException {
    return PARSER.parseFrom(input, extensionRegistry);
  }

  public static Builder newBuilder() { return Builder.create(); }
  public Builder newBuilderForType() { return newBuilder(); }
  public static Builder newBuilder(SubscribeReq prototype) {
    return newBuilder().mergeFrom(prototype);
  }
  public Builder toBuilder() { return newBuilder(this); }

  @Override
  protected Builder newBuilderForType(
      BuilderParent parent) {
    Builder builder = new Builder(parent);
    return builder;
  }
  /**
   * Protobuf type {@code echo.cn.SubscribeReq}
   */
  public static final class Builder extends
      com.google.protobuf.GeneratedMessage.Builder<Builder>
     implements SubscribeReqOrBuilder {
    public static final com.google.protobuf.Descriptors.Descriptor
        getDescriptor() {
      return SubscribeReqProto.internal_static_echo_cn_SubscribeReq_descriptor;
    }

    protected FieldAccessorTable
        internalGetFieldAccessorTable() {
      return SubscribeReqProto.internal_static_echo_cn_SubscribeReq_fieldAccessorTable
          .ensureFieldAccessorsInitialized(
              SubscribeReq.class, Builder.class);
    }

    // Construct using echo.cn.SubscribeReq.newBuilder()
    private Builder() {
      maybeForceBuilderInitialization();
    }

    private Builder(
        BuilderParent parent) {
      super(parent);
      maybeForceBuilderInitialization();
    }
    private void maybeForceBuilderInitialization() {
      if (com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders) {
      }
    }
    private static Builder create() {
      return new Builder();
    }

    public Builder clear() {
      super.clear();
      subReqID_ = 0;
      bitField0_ = (bitField0_ & ~0x00000001);
      userName_ = "";
      bitField0_ = (bitField0_ & ~0x00000002);
      productName_ = "";
      bitField0_ = (bitField0_ & ~0x00000004);
      phoneNumber_ = "";
      bitField0_ = (bitField0_ & ~0x00000008);
      address_ = "";
      bitField0_ = (bitField0_ & ~0x00000010);
      return this;
    }

    public Builder clone() {
      return create().mergeFrom(buildPartial());
    }

    public com.google.protobuf.Descriptors.Descriptor
        getDescriptorForType() {
      return SubscribeReqProto.internal_static_echo_cn_SubscribeReq_descriptor;
    }

    public SubscribeReq getDefaultInstanceForType() {
      return SubscribeReq.getDefaultInstance();
    }

    public SubscribeReq build() {
      SubscribeReq result = buildPartial();
      if (!result.isInitialized()) {
        throw newUninitializedMessageException(result);
      }
      return result;
    }

    public SubscribeReq buildPartial() {
      SubscribeReq result = new SubscribeReq(this);
      int from_bitField0_ = bitField0_;
      int to_bitField0_ = 0;
      if (((from_bitField0_ & 0x00000001) == 0x00000001)) {
        to_bitField0_ |= 0x00000001;
      }
      result.subReqID_ = subReqID_;
      if (((from_bitField0_ & 0x00000002) == 0x00000002)) {
        to_bitField0_ |= 0x00000002;
      }
      result.userName_ = userName_;
      if (((from_bitField0_ & 0x00000004) == 0x00000004)) {
        to_bitField0_ |= 0x00000004;
      }
      result.productName_ = productName_;
      if (((from_bitField0_ & 0x00000008) == 0x00000008)) {
        to_bitField0_ |= 0x00000008;
      }
      result.phoneNumber_ = phoneNumber_;
      if (((from_bitField0_ & 0x00000010) == 0x00000010)) {
        to_bitField0_ |= 0x00000010;
      }
      result.address_ = address_;
      result.bitField0_ = to_bitField0_;
      onBuilt();
      return result;
    }

    public Builder mergeFrom(com.google.protobuf.Message other) {
      if (other instanceof SubscribeReq) {
        return mergeFrom((SubscribeReq)other);
      } else {
        super.mergeFrom(other);
        return this;
      }
    }

    public Builder mergeFrom(SubscribeReq other) {
      if (other == SubscribeReq.getDefaultInstance()) return this;
      if (other.hasSubReqID()) {
        setSubReqID(other.getSubReqID());
      }
      if (other.hasUserName()) {
        bitField0_ |= 0x00000002;
        userName_ = other.userName_;
        onChanged();
      }
      if (other.hasProductName()) {
        bitField0_ |= 0x00000004;
        productName_ = other.productName_;
        onChanged();
      }
      if (other.hasPhoneNumber()) {
        bitField0_ |= 0x00000008;
        phoneNumber_ = other.phoneNumber_;
        onChanged();
      }
      if (other.hasAddress()) {
        bitField0_ |= 0x00000010;
        address_ = other.address_;
        onChanged();
      }
      this.mergeUnknownFields(other.getUnknownFields());
      return this;
    }

    public final boolean isInitialized() {
      if (!hasSubReqID()) {
        
        return false;
      }
      if (!hasUserName()) {
        
        return false;
      }
      if (!hasProductName()) {
        
        return false;
      }
      if (!hasPhoneNumber()) {
        
        return false;
      }
      if (!hasAddress()) {
        
        return false;
      }
      return true;
    }

    public Builder mergeFrom(
        com.google.protobuf.CodedInputStream input,
        com.google.protobuf.ExtensionRegistryLite extensionRegistry)
        throws java.io.IOException {
      SubscribeReq parsedMessage = null;
      try {
        parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry);
      } catch (com.google.protobuf.InvalidProtocolBufferException e) {
        parsedMessage = (SubscribeReq) e.getUnfinishedMessage();
        throw e;
      } finally {
        if (parsedMessage != null) {
          mergeFrom(parsedMessage);
        }
      }
      return this;
    }
    private int bitField0_;

    // required int32 subReqID = 1;
    private int subReqID_ ;
    /**
     * <code>required int32 subReqID = 1;</code>
     */
    public boolean hasSubReqID() {
      return ((bitField0_ & 0x00000001) == 0x00000001);
    }
    /**
     * <code>required int32 subReqID = 1;</code>
     */
    public int getSubReqID() {
      return subReqID_;
    }
    /**
     * <code>required int32 subReqID = 1;</code>
     */
    public Builder setSubReqID(int value) {
      bitField0_ |= 0x00000001;
      subReqID_ = value;
      onChanged();
      return this;
    }
    /**
     * <code>required int32 subReqID = 1;</code>
     */
    public Builder clearSubReqID() {
      bitField0_ = (bitField0_ & ~0x00000001);
      subReqID_ = 0;
      onChanged();
      return this;
    }

    // required string userName = 2;
    private Object userName_ = "";
    /**
     * <code>required string userName = 2;</code>
     */
    public boolean hasUserName() {
      return ((bitField0_ & 0x00000002) == 0x00000002);
    }
    /**
     * <code>required string userName = 2;</code>
     */
    public String getUserName() {
      Object ref = userName_;
      if (!(ref instanceof String)) {
        String s = ((com.google.protobuf.ByteString) ref)
            .toStringUtf8();
        userName_ = s;
        return s;
      } else {
        return (String) ref;
      }
    }
    /**
     * <code>required string userName = 2;</code>
     */
    public com.google.protobuf.ByteString
        getUserNameBytes() {
      Object ref = userName_;
      if (ref instanceof String) {
        com.google.protobuf.ByteString b = 
            com.google.protobuf.ByteString.copyFromUtf8(
                (String) ref);
        userName_ = b;
        return b;
      } else {
        return (com.google.protobuf.ByteString) ref;
      }
    }
    /**
     * <code>required string userName = 2;</code>
     */
    public Builder setUserName(
        String value) {
      if (value == null) {
    throw new NullPointerException();
  }
  bitField0_ |= 0x00000002;
      userName_ = value;
      onChanged();
      return this;
    }
    /**
     * <code>required string userName = 2;</code>
     */
    public Builder clearUserName() {
      bitField0_ = (bitField0_ & ~0x00000002);
      userName_ = getDefaultInstance().getUserName();
      onChanged();
      return this;
    }
    /**
     * <code>required string userName = 2;</code>
     */
    public Builder setUserNameBytes(
        com.google.protobuf.ByteString value) {
      if (value == null) {
    throw new NullPointerException();
  }
  bitField0_ |= 0x00000002;
      userName_ = value;
      onChanged();
      return this;
    }

    // required string productName = 3;
    private Object productName_ = "";
    /**
     * <code>required string productName = 3;</code>
     */
    public boolean hasProductName() {
      return ((bitField0_ & 0x00000004) == 0x00000004);
    }
    /**
     * <code>required string productName = 3;</code>
     */
    public String getProductName() {
      Object ref = productName_;
      if (!(ref instanceof String)) {
        String s = ((com.google.protobuf.ByteString) ref)
            .toStringUtf8();
        productName_ = s;
        return s;
      } else {
        return (String) ref;
      }
    }
    /**
     * <code>required string productName = 3;</code>
     */
    public com.google.protobuf.ByteString
        getProductNameBytes() {
      Object ref = productName_;
      if (ref instanceof String) {
        com.google.protobuf.ByteString b = 
            com.google.protobuf.ByteString.copyFromUtf8(
                (String) ref);
        productName_ = b;
        return b;
      } else {
        return (com.google.protobuf.ByteString) ref;
      }
    }
    /**
     * <code>required string productName = 3;</code>
     */
    public Builder setProductName(
        String value) {
      if (value == null) {
    throw new NullPointerException();
  }
  bitField0_ |= 0x00000004;
      productName_ = value;
      onChanged();
      return this;
    }
    /**
     * <code>required string productName = 3;</code>
     */
    public Builder clearProductName() {
      bitField0_ = (bitField0_ & ~0x00000004);
      productName_ = getDefaultInstance().getProductName();
      onChanged();
      return this;
    }
    /**
     * <code>required string productName = 3;</code>
     */
    public Builder setProductNameBytes(
        com.google.protobuf.ByteString value) {
      if (value == null) {
    throw new NullPointerException();
  }
  bitField0_ |= 0x00000004;
      productName_ = value;
      onChanged();
      return this;
    }

    // required string phoneNumber = 4;
    private Object phoneNumber_ = "";
    /**
     * <code>required string phoneNumber = 4;</code>
     */
    public boolean hasPhoneNumber() {
      return ((bitField0_ & 0x00000008) == 0x00000008);
    }
    /**
     * <code>required string phoneNumber = 4;</code>
     */
    public String getPhoneNumber() {
      Object ref = phoneNumber_;
      if (!(ref instanceof String)) {
        String s = ((com.google.protobuf.ByteString) ref)
            .toStringUtf8();
        phoneNumber_ = s;
        return s;
      } else {
        return (String) ref;
      }
    }
    /**
     * <code>required string phoneNumber = 4;</code>
     */
    public com.google.protobuf.ByteString
        getPhoneNumberBytes() {
      Object ref = phoneNumber_;
      if (ref instanceof String) {
        com.google.protobuf.ByteString b = 
            com.google.protobuf.ByteString.copyFromUtf8(
                (String) ref);
        phoneNumber_ = b;
        return b;
      } else {
        return (com.google.protobuf.ByteString) ref;
      }
    }
    /**
     * <code>required string phoneNumber = 4;</code>
     */
    public Builder setPhoneNumber(
        String value) {
      if (value == null) {
    throw new NullPointerException();
  }
  bitField0_ |= 0x00000008;
      phoneNumber_ = value;
      onChanged();
      return this;
    }
    /**
     * <code>required string phoneNumber = 4;</code>
     */
    public Builder clearPhoneNumber() {
      bitField0_ = (bitField0_ & ~0x00000008);
      phoneNumber_ = getDefaultInstance().getPhoneNumber();
      onChanged();
      return this;
    }
    /**
     * <code>required string phoneNumber = 4;</code>
     */
    public Builder setPhoneNumberBytes(
        com.google.protobuf.ByteString value) {
      if (value == null) {
    throw new NullPointerException();
  }
  bitField0_ |= 0x00000008;
      phoneNumber_ = value;
      onChanged();
      return this;
    }

    // required string address = 5;
    private Object address_ = "";
    /**
     * <code>required string address = 5;</code>
     */
    public boolean hasAddress() {
      return ((bitField0_ & 0x00000010) == 0x00000010);
    }
    /**
     * <code>required string address = 5;</code>
     */
    public String getAddress() {
      Object ref = address_;
      if (!(ref instanceof String)) {
        String s = ((com.google.protobuf.ByteString) ref)
            .toStringUtf8();
        address_ = s;
        return s;
      } else {
        return (String) ref;
      }
    }
    /**
     * <code>required string address = 5;</code>
     */
    public com.google.protobuf.ByteString
        getAddressBytes() {
      Object ref = address_;
      if (ref instanceof String) {
        com.google.protobuf.ByteString b = 
            com.google.protobuf.ByteString.copyFromUtf8(
                (String) ref);
        address_ = b;
        return b;
      } else {
        return (com.google.protobuf.ByteString) ref;
      }
    }
    /**
     * <code>required string address = 5;</code>
     */
    public Builder setAddress(
        String value) {
      if (value == null) {
    throw new NullPointerException();
  }
  bitField0_ |= 0x00000010;
      address_ = value;
      onChanged();
      return this;
    }
    /**
     * <code>required string address = 5;</code>
     */
    public Builder clearAddress() {
      bitField0_ = (bitField0_ & ~0x00000010);
      address_ = getDefaultInstance().getAddress();
      onChanged();
      return this;
    }
    /**
     * <code>required string address = 5;</code>
     */
    public Builder setAddressBytes(
        com.google.protobuf.ByteString value) {
      if (value == null) {
    throw new NullPointerException();
  }
  bitField0_ |= 0x00000010;
      address_ = value;
      onChanged();
      return this;
    }

    // @@protoc_insertion_point(builder_scope:echo.cn.SubscribeReq)
  }

  static {
    defaultInstance = new SubscribeReq(true);
    defaultInstance.initFields();
  }

  // @@protoc_insertion_point(class_scope:echo.cn.SubscribeReq)
}


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

package echo.cn;

public interface SubscribeReqOrBuilder
    extends com.google.protobuf.MessageOrBuilder {

  // required int32 subReqID = 1;
  /**
   * <code>required int32 subReqID = 1;</code>
   */
  boolean hasSubReqID();
  /**
   * <code>required int32 subReqID = 1;</code>
   */
  int getSubReqID();

  // required string userName = 2;
  /**
   * <code>required string userName = 2;</code>
   */
  boolean hasUserName();
  /**
   * <code>required string userName = 2;</code>
   */
  String getUserName();
  /**
   * <code>required string userName = 2;</code>
   */
  com.google.protobuf.ByteString
      getUserNameBytes();

  // required string productName = 3;
  /**
   * <code>required string productName = 3;</code>
   */
  boolean hasProductName();
  /**
   * <code>required string productName = 3;</code>
   */
  String getProductName();
  /**
   * <code>required string productName = 3;</code>
   */
  com.google.protobuf.ByteString
      getProductNameBytes();

  // required string phoneNumber = 4;
  /**
   * <code>required string phoneNumber = 4;</code>
   */
  boolean hasPhoneNumber();
  /**
   * <code>required string phoneNumber = 4;</code>
   */
  String getPhoneNumber();
  /**
   * <code>required string phoneNumber = 4;</code>
   */
  com.google.protobuf.ByteString
      getPhoneNumberBytes();

  // required string address = 5;
  /**
   * <code>required string address = 5;</code>
   */
  boolean hasAddress();
  /**
   * <code>required string address = 5;</code>
   */
  String getAddress();
  /**
   * <code>required string address = 5;</code>
   */
  com.google.protobuf.ByteString
      getAddressBytes();
}

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

package echo.cn;

public final class SubscribeReqProto {
  private SubscribeReqProto() {}
  public static void registerAllExtensions(
      com.google.protobuf.ExtensionRegistry registry) {
  }
  static com.google.protobuf.Descriptors.Descriptor
    internal_static_echo_cn_SubscribeReq_descriptor;
  static
    com.google.protobuf.GeneratedMessage.FieldAccessorTable
      internal_static_echo_cn_SubscribeReq_fieldAccessorTable;

  public static com.google.protobuf.Descriptors.FileDescriptor
      getDescriptor() {
    return descriptor;
  }
  private static com.google.protobuf.Descriptors.FileDescriptor
      descriptor;
  static {
    String[] descriptorData = {
      "\n\022SubscribeReq.proto\022\007echo.cn\"m\n\014Subscri" +
      "beReq\022\020\n\010subReqID\030\001 \002(\005\022\020\n\010userName\030\002 \002(" +
      "\t\022\023\n\013productName\030\003 \002(\t\022\023\n\013phoneNumber\030\004 " +
      "\002(\t\022\017\n\007address\030\005 \002(\tB\036\n\007echo.cnB\021Subscri" +
      "beReqProtoP\001"
    };
    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;
          internal_static_echo_cn_SubscribeReq_descriptor =
            getDescriptor().getMessageTypes().get(0);
          internal_static_echo_cn_SubscribeReq_fieldAccessorTable = new
            com.google.protobuf.GeneratedMessage.FieldAccessorTable(
              internal_static_echo_cn_SubscribeReq_descriptor,
              new String[] { "SubReqID", "UserName", "ProductName", "PhoneNumber", "Address", });
          return null;
        }
      };
    com.google.protobuf.Descriptors.FileDescriptor
      .internalBuildGeneratedFileFrom(descriptorData,
        new com.google.protobuf.Descriptors.FileDescriptor[] {
        }, assigner);
  }

  // @@protoc_insertion_point(outer_class_scope)
}

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

package echo.cn;

/**
 * Protobuf type {@code echo.cn.SubscribeResp}
 */
public  final class SubscribeResp extends
    com.google.protobuf.GeneratedMessage
    implements SubscribeRespOrBuilder {
  // Use SubscribeResp.newBuilder() to construct.
  private SubscribeResp(com.google.protobuf.GeneratedMessage.Builder<?> builder) {
    super(builder);
    this.unknownFields = builder.getUnknownFields();
  }
  private SubscribeResp(boolean noInit) { this.unknownFields = com.google.protobuf.UnknownFieldSet.getDefaultInstance(); }

  private static final SubscribeResp defaultInstance;
  public static SubscribeResp getDefaultInstance() {
    return defaultInstance;
  }

  public SubscribeResp getDefaultInstanceForType() {
    return defaultInstance;
  }

  private final com.google.protobuf.UnknownFieldSet unknownFields;
  @Override
  public final com.google.protobuf.UnknownFieldSet
      getUnknownFields() {
    return this.unknownFields;
  }
  private SubscribeResp(
      com.google.protobuf.CodedInputStream input,
      com.google.protobuf.ExtensionRegistryLite extensionRegistry)
      throws com.google.protobuf.InvalidProtocolBufferException {
    initFields();
    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;
          default: {
            if (!parseUnknownField(input, unknownFields,
                                   extensionRegistry, tag)) {
              done = true;
            }
            break;
          }
          case 8: {
            bitField0_ |= 0x00000001;
            subReqID_ = input.readInt32();
            break;
          }
          case 16: {
            bitField0_ |= 0x00000002;
            respCode_ = input.readInt32();
            break;
          }
          case 26: {
            bitField0_ |= 0x00000004;
            desc_ = input.readBytes();
            break;
          }
        }
      }
    } catch (com.google.protobuf.InvalidProtocolBufferException e) {
      throw e.setUnfinishedMessage(this);
    } catch (java.io.IOException e) {
      throw new com.google.protobuf.InvalidProtocolBufferException(
          e.getMessage()).setUnfinishedMessage(this);
    } finally {
      this.unknownFields = unknownFields.build();
      makeExtensionsImmutable();
    }
  }
  public static final com.google.protobuf.Descriptors.Descriptor
      getDescriptor() {
    return SubscribeRespProto.internal_static_echo_cn_SubscribeResp_descriptor;
  }

  protected FieldAccessorTable
      internalGetFieldAccessorTable() {
    return SubscribeRespProto.internal_static_echo_cn_SubscribeResp_fieldAccessorTable
        .ensureFieldAccessorsInitialized(
            SubscribeResp.class, Builder.class);
  }

  public static com.google.protobuf.Parser<SubscribeResp> PARSER =
      new com.google.protobuf.AbstractParser<SubscribeResp>() {
    public SubscribeResp parsePartialFrom(
        com.google.protobuf.CodedInputStream input,
        com.google.protobuf.ExtensionRegistryLite extensionRegistry)
        throws com.google.protobuf.InvalidProtocolBufferException {
      return new SubscribeResp(input, extensionRegistry);
    }
  };

  @Override
  public com.google.protobuf.Parser<SubscribeResp> getParserForType() {
    return PARSER;
  }

  private int bitField0_;
  // required int32 subReqID = 1;
  public static final int SUBREQID_FIELD_NUMBER = 1;
  private int subReqID_;
  /**
   * <code>required int32 subReqID = 1;</code>
   */
  public boolean hasSubReqID() {
    return ((bitField0_ & 0x00000001) == 0x00000001);
  }
  /**
   * <code>required int32 subReqID = 1;</code>
   */
  public int getSubReqID() {
    return subReqID_;
  }

  // required int32 respCode = 2;
  public static final int RESPCODE_FIELD_NUMBER = 2;
  private int respCode_;
  /**
   * <code>required int32 respCode = 2;</code>
   */
  public boolean hasRespCode() {
    return ((bitField0_ & 0x00000002) == 0x00000002);
  }
  /**
   * <code>required int32 respCode = 2;</code>
   */
  public int getRespCode() {
    return respCode_;
  }

  // required string desc = 3;
  public static final int DESC_FIELD_NUMBER = 3;
  private Object desc_;
  /**
   * <code>required string desc = 3;</code>
   */
  public boolean hasDesc() {
    return ((bitField0_ & 0x00000004) == 0x00000004);
  }
  /**
   * <code>required string desc = 3;</code>
   */
  public String getDesc() {
    Object ref = desc_;
    if (ref instanceof String) {
      return (String) ref;
    } else {
      com.google.protobuf.ByteString bs = 
          (com.google.protobuf.ByteString) ref;
      String s = bs.toStringUtf8();
      if (bs.isValidUtf8()) {
        desc_ = s;
      }
      return s;
    }
  }
  /**
   * <code>required string desc = 3;</code>
   */
  public com.google.protobuf.ByteString
      getDescBytes() {
    Object ref = desc_;
    if (ref instanceof String) {
      com.google.protobuf.ByteString b = 
          com.google.protobuf.ByteString.copyFromUtf8(
              (String) ref);
      desc_ = b;
      return b;
    } else {
      return (com.google.protobuf.ByteString) ref;
    }
  }

  private void initFields() {
    subReqID_ = 0;
    respCode_ = 0;
    desc_ = "";
  }
  private byte memoizedIsInitialized = -1;
  public final boolean isInitialized() {
    byte isInitialized = memoizedIsInitialized;
    if (isInitialized != -1) return isInitialized == 1;

    if (!hasSubReqID()) {
      memoizedIsInitialized = 0;
      return false;
    }
    if (!hasRespCode()) {
      memoizedIsInitialized = 0;
      return false;
    }
    if (!hasDesc()) {
      memoizedIsInitialized = 0;
      return false;
    }
    memoizedIsInitialized = 1;
    return true;
  }

  public void writeTo(com.google.protobuf.CodedOutputStream output)
                      throws java.io.IOException {
    getSerializedSize();
    if (((bitField0_ & 0x00000001) == 0x00000001)) {
      output.writeInt32(1, subReqID_);
    }
    if (((bitField0_ & 0x00000002) == 0x00000002)) {
      output.writeInt32(2, respCode_);
    }
    if (((bitField0_ & 0x00000004) == 0x00000004)) {
      output.writeBytes(3, getDescBytes());
    }
    getUnknownFields().writeTo(output);
  }

  private int memoizedSerializedSize = -1;
  public int getSerializedSize() {
    int size = memoizedSerializedSize;
    if (size != -1) return size;

    size = 0;
    if (((bitField0_ & 0x00000001) == 0x00000001)) {
      size += com.google.protobuf.CodedOutputStream
        .computeInt32Size(1, subReqID_);
    }
    if (((bitField0_ & 0x00000002) == 0x00000002)) {
      size += com.google.protobuf.CodedOutputStream
        .computeInt32Size(2, respCode_);
    }
    if (((bitField0_ & 0x00000004) == 0x00000004)) {
      size += com.google.protobuf.CodedOutputStream
        .computeBytesSize(3, getDescBytes());
    }
    size += getUnknownFields().getSerializedSize();
    memoizedSerializedSize = size;
    return size;
  }

  private static final long serialVersionUID = 0L;
  @Override
  protected Object writeReplace()
      throws java.io.ObjectStreamException {
    return super.writeReplace();
  }

  public static SubscribeResp parseFrom(
      com.google.protobuf.ByteString data)
      throws com.google.protobuf.InvalidProtocolBufferException {
    return PARSER.parseFrom(data);
  }
  public static SubscribeResp parseFrom(
      com.google.protobuf.ByteString data,
      com.google.protobuf.ExtensionRegistryLite extensionRegistry)
      throws com.google.protobuf.InvalidProtocolBufferException {
    return PARSER.parseFrom(data, extensionRegistry);
  }
  public static SubscribeResp parseFrom(byte[] data)
      throws com.google.protobuf.InvalidProtocolBufferException {
    return PARSER.parseFrom(data);
  }
  public static SubscribeResp parseFrom(
      byte[] data,
      com.google.protobuf.ExtensionRegistryLite extensionRegistry)
      throws com.google.protobuf.InvalidProtocolBufferException {
    return PARSER.parseFrom(data, extensionRegistry);
  }
  public static SubscribeResp parseFrom(java.io.InputStream input)
      throws java.io.IOException {
    return PARSER.parseFrom(input);
  }
  public static SubscribeResp parseFrom(
      java.io.InputStream input,
      com.google.protobuf.ExtensionRegistryLite extensionRegistry)
      throws java.io.IOException {
    return PARSER.parseFrom(input, extensionRegistry);
  }
  public static SubscribeResp parseDelimitedFrom(java.io.InputStream input)
      throws java.io.IOException {
    return PARSER.parseDelimitedFrom(input);
  }
  public static SubscribeResp parseDelimitedFrom(
      java.io.InputStream input,
      com.google.protobuf.ExtensionRegistryLite extensionRegistry)
      throws java.io.IOException {
    return PARSER.parseDelimitedFrom(input, extensionRegistry);
  }
  public static SubscribeResp parseFrom(
      com.google.protobuf.CodedInputStream input)
      throws java.io.IOException {
    return PARSER.parseFrom(input);
  }
  public static SubscribeResp parseFrom(
      com.google.protobuf.CodedInputStream input,
      com.google.protobuf.ExtensionRegistryLite extensionRegistry)
      throws java.io.IOException {
    return PARSER.parseFrom(input, extensionRegistry);
  }

  public static Builder newBuilder() { return Builder.create(); }
  public Builder newBuilderForType() { return newBuilder(); }
  public static Builder newBuilder(SubscribeResp prototype) {
    return newBuilder().mergeFrom(prototype);
  }
  public Builder toBuilder() { return newBuilder(this); }

  @Override
  protected Builder newBuilderForType(
      BuilderParent parent) {
    Builder builder = new Builder(parent);
    return builder;
  }
  /**
   * Protobuf type {@code echo.cn.SubscribeResp}
   */
  public static final class Builder extends
      com.google.protobuf.GeneratedMessage.Builder<Builder>
     implements SubscribeRespOrBuilder {
    public static final com.google.protobuf.Descriptors.Descriptor
        getDescriptor() {
      return SubscribeRespProto.internal_static_echo_cn_SubscribeResp_descriptor;
    }

    protected FieldAccessorTable
        internalGetFieldAccessorTable() {
      return SubscribeRespProto.internal_static_echo_cn_SubscribeResp_fieldAccessorTable
          .ensureFieldAccessorsInitialized(
              SubscribeResp.class, Builder.class);
    }

    // Construct using echo.cn.SubscribeResp.newBuilder()
    private Builder() {
      maybeForceBuilderInitialization();
    }

    private Builder(
        BuilderParent parent) {
      super(parent);
      maybeForceBuilderInitialization();
    }
    private void maybeForceBuilderInitialization() {
      if (com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders) {
      }
    }
    private static Builder create() {
      return new Builder();
    }

    public Builder clear() {
      super.clear();
      subReqID_ = 0;
      bitField0_ = (bitField0_ & ~0x00000001);
      respCode_ = 0;
      bitField0_ = (bitField0_ & ~0x00000002);
      desc_ = "";
      bitField0_ = (bitField0_ & ~0x00000004);
      return this;
    }

    public Builder clone() {
      return create().mergeFrom(buildPartial());
    }

    public com.google.protobuf.Descriptors.Descriptor
        getDescriptorForType() {
      return SubscribeRespProto.internal_static_echo_cn_SubscribeResp_descriptor;
    }

    public SubscribeResp getDefaultInstanceForType() {
      return SubscribeResp.getDefaultInstance();
    }

    public SubscribeResp build() {
      SubscribeResp result = buildPartial();
      if (!result.isInitialized()) {
        throw newUninitializedMessageException(result);
      }
      return result;
    }

    public SubscribeResp buildPartial() {
      SubscribeResp result = new SubscribeResp(this);
      int from_bitField0_ = bitField0_;
      int to_bitField0_ = 0;
      if (((from_bitField0_ & 0x00000001) == 0x00000001)) {
        to_bitField0_ |= 0x00000001;
      }
      result.subReqID_ = subReqID_;
      if (((from_bitField0_ & 0x00000002) == 0x00000002)) {
        to_bitField0_ |= 0x00000002;
      }
      result.respCode_ = respCode_;
      if (((from_bitField0_ & 0x00000004) == 0x00000004)) {
        to_bitField0_ |= 0x00000004;
      }
      result.desc_ = desc_;
      result.bitField0_ = to_bitField0_;
      onBuilt();
      return result;
    }

    public Builder mergeFrom(com.google.protobuf.Message other) {
      if (other instanceof SubscribeResp) {
        return mergeFrom((SubscribeResp)other);
      } else {
        super.mergeFrom(other);
        return this;
      }
    }

    public Builder mergeFrom(SubscribeResp other) {
      if (other == SubscribeResp.getDefaultInstance()) return this;
      if (other.hasSubReqID()) {
        setSubReqID(other.getSubReqID());
      }
      if (other.hasRespCode()) {
        setRespCode(other.getRespCode());
      }
      if (other.hasDesc()) {
        bitField0_ |= 0x00000004;
        desc_ = other.desc_;
        onChanged();
      }
      this.mergeUnknownFields(other.getUnknownFields());
      return this;
    }

    public final boolean isInitialized() {
      if (!hasSubReqID()) {
        
        return false;
      }
      if (!hasRespCode()) {
        
        return false;
      }
      if (!hasDesc()) {
        
        return false;
      }
      return true;
    }

    public Builder mergeFrom(
        com.google.protobuf.CodedInputStream input,
        com.google.protobuf.ExtensionRegistryLite extensionRegistry)
        throws java.io.IOException {
      SubscribeResp parsedMessage = null;
      try {
        parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry);
      } catch (com.google.protobuf.InvalidProtocolBufferException e) {
        parsedMessage = (SubscribeResp) e.getUnfinishedMessage();
        throw e;
      } finally {
        if (parsedMessage != null) {
          mergeFrom(parsedMessage);
        }
      }
      return this;
    }
    private int bitField0_;

    // required int32 subReqID = 1;
    private int subReqID_ ;
    /**
     * <code>required int32 subReqID = 1;</code>
     */
    public boolean hasSubReqID() {
      return ((bitField0_ & 0x00000001) == 0x00000001);
    }
    /**
     * <code>required int32 subReqID = 1;</code>
     */
    public int getSubReqID() {
      return subReqID_;
    }
    /**
     * <code>required int32 subReqID = 1;</code>
     */
    public Builder setSubReqID(int value) {
      bitField0_ |= 0x00000001;
      subReqID_ = value;
      onChanged();
      return this;
    }
    /**
     * <code>required int32 subReqID = 1;</code>
     */
    public Builder clearSubReqID() {
      bitField0_ = (bitField0_ & ~0x00000001);
      subReqID_ = 0;
      onChanged();
      return this;
    }

    // required int32 respCode = 2;
    private int respCode_ ;
    /**
     * <code>required int32 respCode = 2;</code>
     */
    public boolean hasRespCode() {
      return ((bitField0_ & 0x00000002) == 0x00000002);
    }
    /**
     * <code>required int32 respCode = 2;</code>
     */
    public int getRespCode() {
      return respCode_;
    }
    /**
     * <code>required int32 respCode = 2;</code>
     */
    public Builder setRespCode(int value) {
      bitField0_ |= 0x00000002;
      respCode_ = value;
      onChanged();
      return this;
    }
    /**
     * <code>required int32 respCode = 2;</code>
     */
    public Builder clearRespCode() {
      bitField0_ = (bitField0_ & ~0x00000002);
      respCode_ = 0;
      onChanged();
      return this;
    }

    // required string desc = 3;
    private Object desc_ = "";
    /**
     * <code>required string desc = 3;</code>
     */
    public boolean hasDesc() {
      return ((bitField0_ & 0x00000004) == 0x00000004);
    }
    /**
     * <code>required string desc = 3;</code>
     */
    public String getDesc() {
      Object ref = desc_;
      if (!(ref instanceof String)) {
        String s = ((com.google.protobuf.ByteString) ref)
            .toStringUtf8();
        desc_ = s;
        return s;
      } else {
        return (String) ref;
      }
    }
    /**
     * <code>required string desc = 3;</code>
     */
    public com.google.protobuf.ByteString
        getDescBytes() {
      Object ref = desc_;
      if (ref instanceof String) {
        com.google.protobuf.ByteString b = 
            com.google.protobuf.ByteString.copyFromUtf8(
                (String) ref);
        desc_ = b;
        return b;
      } else {
        return (com.google.protobuf.ByteString) ref;
      }
    }
    /**
     * <code>required string desc = 3;</code>
     */
    public Builder setDesc(
        String value) {
      if (value == null) {
    throw new NullPointerException();
  }
  bitField0_ |= 0x00000004;
      desc_ = value;
      onChanged();
      return this;
    }
    /**
     * <code>required string desc = 3;</code>
     */
    public Builder clearDesc() {
      bitField0_ = (bitField0_ & ~0x00000004);
      desc_ = getDefaultInstance().getDesc();
      onChanged();
      return this;
    }
    /**
     * <code>required string desc = 3;</code>
     */
    public Builder setDescBytes(
        com.google.protobuf.ByteString value) {
      if (value == null) {
    throw new NullPointerException();
  }
  bitField0_ |= 0x00000004;
      desc_ = value;
      onChanged();
      return this;
    }

    // @@protoc_insertion_point(builder_scope:echo.cn.SubscribeResp)
  }

  static {
    defaultInstance = new SubscribeResp(true);
    defaultInstance.initFields();
  }

  // @@protoc_insertion_point(class_scope:echo.cn.SubscribeResp)
}


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

package echo.cn;

public interface SubscribeRespOrBuilder
    extends com.google.protobuf.MessageOrBuilder {

  // required int32 subReqID = 1;
  /**
   * <code>required int32 subReqID = 1;</code>
   */
  boolean hasSubReqID();
  /**
   * <code>required int32 subReqID = 1;</code>
   */
  int getSubReqID();

  // required int32 respCode = 2;
  /**
   * <code>required int32 respCode = 2;</code>
   */
  boolean hasRespCode();
  /**
   * <code>required int32 respCode = 2;</code>
   */
  int getRespCode();

  // required string desc = 3;
  /**
   * <code>required string desc = 3;</code>
   */
  boolean hasDesc();
  /**
   * <code>required string desc = 3;</code>
   */
  String getDesc();
  /**
   * <code>required string desc = 3;</code>
   */
  com.google.protobuf.ByteString
      getDescBytes();
}

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

package echo.cn;

public final class SubscribeRespProto {
  private SubscribeRespProto() {}
  public static void registerAllExtensions(
      com.google.protobuf.ExtensionRegistry registry) {
  }
  static com.google.protobuf.Descriptors.Descriptor
    internal_static_echo_cn_SubscribeResp_descriptor;
  static
    com.google.protobuf.GeneratedMessage.FieldAccessorTable
      internal_static_echo_cn_SubscribeResp_fieldAccessorTable;

  public static com.google.protobuf.Descriptors.FileDescriptor
      getDescriptor() {
    return descriptor;
  }
  private static com.google.protobuf.Descriptors.FileDescriptor
      descriptor;
  static {
    String[] descriptorData = {
      "\n\023SubscribeResp.proto\022\007echo.cn\"A\n\rSubscr" +
      "ibeResp\022\020\n\010subReqID\030\001 \002(\005\022\020\n\010respCode\030\002 " +
      "\002(\005\022\014\n\004desc\030\003 \002(\tB\037\n\007echo.cnB\022SubscribeR" +
      "espProtoP\001"
    };
    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;
          internal_static_echo_cn_SubscribeResp_descriptor =
            getDescriptor().getMessageTypes().get(0);
          internal_static_echo_cn_SubscribeResp_fieldAccessorTable = new
            com.google.protobuf.GeneratedMessage.FieldAccessorTable(
              internal_static_echo_cn_SubscribeResp_descriptor,
              new String[] { "SubReqID", "RespCode", "Desc", });
          return null;
        }
      };
    com.google.protobuf.Descriptors.FileDescriptor
      .internalBuildGeneratedFileFrom(descriptorData,
        new com.google.protobuf.Descriptors.FileDescriptor[] {
        }, assigner);
  }

  // @@protoc_insertion_point(outer_class_scope)
}

服务端客户端启动效果截图

服务端打印

在这里插入图片描述

客户端打印截图

在这里插入图片描述

Protobuf的使用注意事项

ProtobufDecoder 仅仅负责解码,它不支持读半包。因此 在 ProtobufDecoder 前面,一定要有能够处理读半包的解码器。有三种选择:
(1)使用Netty提供的ProtobufVarint32FrameDecoder
(2)继承Netty 提供的通用半包解码器 LengthFieldBaseedFrameDecoder
(3)继承ByteToMessageDecoder类,自定义半包处理逻辑。
读者可以注释掉 服务端启动类的 ProtobufVarint32FrameDecoder.会发现问题。
在这里插入图片描述

总结

首先在Protobuf的入门知识中,通过简单的样例代码熟悉如何用Protobuf对POJO对象进行编码。利用protoc.exe 编译.proto文件可能对于不熟悉的同学比较难,需要多实操几次。在掌握了Protobuf的基础知识之后,讲解如何使用Netty 的Protobuf进行客户端和服务端开发,最后对Protobuf解码器需要注意点进行了说明。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值