首页 > 技术文章 > Google Protocol Buffer入门

small-k 2018-01-14 12:10 原文

简介

Google Protocol Buffer( 简称 Protobuf) 是 Google 公司内部的混合语言数据标准,目前已经正在使用的有超过 48,162 种报文格式定义和超过 12,183 个 .proto 文件。他们用于 RPC 系统和持续数据存储系统。

Protocol Buffers 是一种轻便高效的结构化数据存储格式,可以用于结构化数据串行化,或者说序列化。它很适合做数据存储或 RPC 数据交换格式。可用于通讯协议、数据存储等领域的语言无关、平台无关、可扩展的序列化结构数据格式。目前提供了 C++、Java、Python 三种语言的 API。

如果你在开发中使用过常用的数据交换格式如xml、json,那么protocol buffer也不是什么神奇的东西了,它和xml、json类似,也可以作为开发中的一种数据交换格式,只不过相较xml和json,protocol buffer的优点更明显,它更小、更快、更简单。

windows下使用Protobuf

对于非C++用户,可以直接下载官网预编译好的protoc.exe(install the protocol compiler is to download a pre-built binary):
https://repo1.maven.org/maven2/com/google/protobuf/protoc/

对于C++用户,可以下载源码编译生成proto.exe。

Java中使用ProtocolBuffer

在Java中使用ProtocolBuffer的步骤大致分为下面这几点:

  • (1)编写.proto文件,定义消息类型

application.proto

syntax = "proto2";
package proto;
option java_package = "com.ziyun.bean.proto";
option java_outer_classname = "IpAddress";
message ip_address {
    optional string af = 1;
    optional string addr = 2;
}
  • (2)使用ProtocolBuffer的编译器(protoc.exe),将.proto文件编译成对应的java文件.
    生成java对象的通用工具类
public class GenereteBeanUtil {

    /**
     * 通过执行cmd命令调用protoc.exe程序
     * 参考命令:protoc2.exe -I=./ --java_out=./ ./proto/access_point.proto
     *
     * @param absolutePath  exe程序绝对路径
     * @param protoFileName proto文件名
     */
    public static void generateBean(String absolutePath, String protoFileName) {
        String[] cmd = {absolutePath + "protoc2.exe", "-I=" + absolutePath, "--java_out=" + absolutePath,
                absolutePath + "proto/" + protoFileName};
        try {
            Runtime.getRuntime().exec(cmd);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) throws IOException {
        File directory = new File("");
        String absolutePath = directory.getAbsolutePath();

        //proto文件路径
        String protoPath = absolutePath + File.separator + "zy-libs" + File.separator + "zy-zeromq"
                + File.separator + "src" + File.separator + "main" + File.separator + "java" + File.separator +
                "proto" + File.separator;
        String dirPath = absolutePath + File.separator + "zy-libs" + File.separator + "zy-zeromq" + File.separator +
                "src" + File.separator + "main" + File.separator + "java" + File.separator;

        File dir = new File(protoPath);
        File[] files = dir.listFiles();
        for (File file : files) {
            String fileName = file.getName();
            GenereteBeanUtil.generateBean(dirPath, fileName);
        }
    }
}

通过工具类生成的java对象

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

package com.ziyun.bean.proto;

public final class IpAddress {
  private IpAddress() {}
  public static void registerAllExtensions(
      com.google.protobuf.ExtensionRegistry registry) {
  }
  public interface ip_addressOrBuilder extends
      // @@protoc_insertion_point(interface_extends:proto.ip_address)
      com.google.protobuf.MessageOrBuilder {

    /**
     * <code>optional string af = 1;</code>
     */
    boolean hasAf();
    /**
     * <code>optional string af = 1;</code>
     */
    java.lang.String getAf();
    /**
     * <code>optional string af = 1;</code>
     */
    com.google.protobuf.ByteString
        getAfBytes();

    /**
     * <code>optional string addr = 2;</code>
     */
    boolean hasAddr();
    /**
     * <code>optional string addr = 2;</code>
     */
    java.lang.String getAddr();
    /**
     * <code>optional string addr = 2;</code>
     */
    com.google.protobuf.ByteString
        getAddrBytes();
  }
  /**
   * Protobuf type {@code proto.ip_address}
   */
  public static final class ip_address extends
      com.google.protobuf.GeneratedMessage implements
      // @@protoc_insertion_point(message_implements:proto.ip_address)
      ip_addressOrBuilder {
    // Use ip_address.newBuilder() to construct.
    private ip_address(com.google.protobuf.GeneratedMessage.Builder<?> builder) {
      super(builder);
      this.unknownFields = builder.getUnknownFields();
    }
    private ip_address(boolean noInit) { this.unknownFields = com.google.protobuf.UnknownFieldSet.getDefaultInstance(); }

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

    public ip_address getDefaultInstanceForType() {
      return defaultInstance;
    }

    private final com.google.protobuf.UnknownFieldSet unknownFields;
    @java.lang.Override
    public final com.google.protobuf.UnknownFieldSet
        getUnknownFields() {
      return this.unknownFields;
    }
    private ip_address(
        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 10: {
              com.google.protobuf.ByteString bs = input.readBytes();
              bitField0_ |= 0x00000001;
              af_ = bs;
              break;
            }
            case 18: {
              com.google.protobuf.ByteString bs = input.readBytes();
              bitField0_ |= 0x00000002;
              addr_ = bs;
              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 IpAddress.internal_static_proto_ip_address_descriptor;
    }

    protected com.google.protobuf.GeneratedMessage.FieldAccessorTable
        internalGetFieldAccessorTable() {
      return IpAddress.internal_static_proto_ip_address_fieldAccessorTable
          .ensureFieldAccessorsInitialized(
              IpAddress.ip_address.class, IpAddress.ip_address.Builder.class);
    }

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

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

    private int bitField0_;
    public static final int AF_FIELD_NUMBER = 1;
    private java.lang.Object af_;
    /**
     * <code>optional string af = 1;</code>
     */
    public boolean hasAf() {
      return ((bitField0_ & 0x00000001) == 0x00000001);
    }
    /**
     * <code>optional string af = 1;</code>
     */
    public java.lang.String getAf() {
      java.lang.Object ref = af_;
      if (ref instanceof java.lang.String) {
        return (java.lang.String) ref;
      } else {
        com.google.protobuf.ByteString bs = 
            (com.google.protobuf.ByteString) ref;
        java.lang.String s = bs.toStringUtf8();
        if (bs.isValidUtf8()) {
          af_ = s;
        }
        return s;
      }
    }
    /**
     * <code>optional string af = 1;</code>
     */
    public com.google.protobuf.ByteString
        getAfBytes() {
      java.lang.Object ref = af_;
      if (ref instanceof java.lang.String) {
        com.google.protobuf.ByteString b = 
            com.google.protobuf.ByteString.copyFromUtf8(
                (java.lang.String) ref);
        af_ = b;
        return b;
      } else {
        return (com.google.protobuf.ByteString) ref;
      }
    }

    public static final int ADDR_FIELD_NUMBER = 2;
    private java.lang.Object addr_;
    /**
     * <code>optional string addr = 2;</code>
     */
    public boolean hasAddr() {
      return ((bitField0_ & 0x00000002) == 0x00000002);
    }
    /**
     * <code>optional string addr = 2;</code>
     */
    public java.lang.String getAddr() {
      java.lang.Object ref = addr_;
      if (ref instanceof java.lang.String) {
        return (java.lang.String) ref;
      } else {
        com.google.protobuf.ByteString bs = 
            (com.google.protobuf.ByteString) ref;
        java.lang.String s = bs.toStringUtf8();
        if (bs.isValidUtf8()) {
          addr_ = s;
        }
        return s;
      }
    }
    /**
     * <code>optional string addr = 2;</code>
     */
    public com.google.protobuf.ByteString
        getAddrBytes() {
      java.lang.Object ref = addr_;
      if (ref instanceof java.lang.String) {
        com.google.protobuf.ByteString b = 
            com.google.protobuf.ByteString.copyFromUtf8(
                (java.lang.String) ref);
        addr_ = b;
        return b;
      } else {
        return (com.google.protobuf.ByteString) ref;
      }
    }

    private void initFields() {
      af_ = "";
      addr_ = "";
    }
    private byte memoizedIsInitialized = -1;
    public final boolean isInitialized() {
      byte isInitialized = memoizedIsInitialized;
      if (isInitialized == 1) return true;
      if (isInitialized == 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.writeBytes(1, getAfBytes());
      }
      if (((bitField0_ & 0x00000002) == 0x00000002)) {
        output.writeBytes(2, getAddrBytes());
      }
      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
          .computeBytesSize(1, getAfBytes());
      }
      if (((bitField0_ & 0x00000002) == 0x00000002)) {
        size += com.google.protobuf.CodedOutputStream
          .computeBytesSize(2, getAddrBytes());
      }
      size += getUnknownFields().getSerializedSize();
      memoizedSerializedSize = size;
      return size;
    }

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

    public static IpAddress.ip_address parseFrom(
        com.google.protobuf.ByteString data)
        throws com.google.protobuf.InvalidProtocolBufferException {
      return PARSER.parseFrom(data);
    }
    public static IpAddress.ip_address parseFrom(
        com.google.protobuf.ByteString data,
        com.google.protobuf.ExtensionRegistryLite extensionRegistry)
        throws com.google.protobuf.InvalidProtocolBufferException {
      return PARSER.parseFrom(data, extensionRegistry);
    }
    public static IpAddress.ip_address parseFrom(byte[] data)
        throws com.google.protobuf.InvalidProtocolBufferException {
      return PARSER.parseFrom(data);
    }
    public static IpAddress.ip_address parseFrom(
        byte[] data,
        com.google.protobuf.ExtensionRegistryLite extensionRegistry)
        throws com.google.protobuf.InvalidProtocolBufferException {
      return PARSER.parseFrom(data, extensionRegistry);
    }
    public static IpAddress.ip_address parseFrom(java.io.InputStream input)
        throws java.io.IOException {
      return PARSER.parseFrom(input);
    }
    public static IpAddress.ip_address parseFrom(
        java.io.InputStream input,
        com.google.protobuf.ExtensionRegistryLite extensionRegistry)
        throws java.io.IOException {
      return PARSER.parseFrom(input, extensionRegistry);
    }
    public static IpAddress.ip_address parseDelimitedFrom(java.io.InputStream input)
        throws java.io.IOException {
      return PARSER.parseDelimitedFrom(input);
    }
    public static IpAddress.ip_address parseDelimitedFrom(
        java.io.InputStream input,
        com.google.protobuf.ExtensionRegistryLite extensionRegistry)
        throws java.io.IOException {
      return PARSER.parseDelimitedFrom(input, extensionRegistry);
    }
    public static IpAddress.ip_address parseFrom(
        com.google.protobuf.CodedInputStream input)
        throws java.io.IOException {
      return PARSER.parseFrom(input);
    }
    public static IpAddress.ip_address 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(IpAddress.ip_address prototype) {
      return newBuilder().mergeFrom(prototype);
    }
    public Builder toBuilder() { return newBuilder(this); }

    @java.lang.Override
    protected Builder newBuilderForType(
        com.google.protobuf.GeneratedMessage.BuilderParent parent) {
      Builder builder = new Builder(parent);
      return builder;
    }
    /**
     * Protobuf type {@code proto.ip_address}
     */
    public static final class Builder extends
        com.google.protobuf.GeneratedMessage.Builder<Builder> implements
        // @@protoc_insertion_point(builder_implements:proto.ip_address)
        IpAddress.ip_addressOrBuilder {
      public static final com.google.protobuf.Descriptors.Descriptor
          getDescriptor() {
        return IpAddress.internal_static_proto_ip_address_descriptor;
      }

      protected com.google.protobuf.GeneratedMessage.FieldAccessorTable
          internalGetFieldAccessorTable() {
        return IpAddress.internal_static_proto_ip_address_fieldAccessorTable
            .ensureFieldAccessorsInitialized(
                IpAddress.ip_address.class, IpAddress.ip_address.Builder.class);
      }

      // Construct using com.ziyun.bean.proto.IpAddress.ip_address.newBuilder()
      private Builder() {
        maybeForceBuilderInitialization();
      }

      private Builder(
          com.google.protobuf.GeneratedMessage.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();
        af_ = "";
        bitField0_ = (bitField0_ & ~0x00000001);
        addr_ = "";
        bitField0_ = (bitField0_ & ~0x00000002);
        return this;
      }

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

      public com.google.protobuf.Descriptors.Descriptor
          getDescriptorForType() {
        return IpAddress.internal_static_proto_ip_address_descriptor;
      }

      public IpAddress.ip_address getDefaultInstanceForType() {
        return IpAddress.ip_address.getDefaultInstance();
      }

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

      public IpAddress.ip_address buildPartial() {
        IpAddress.ip_address result = new IpAddress.ip_address(this);
        int from_bitField0_ = bitField0_;
        int to_bitField0_ = 0;
        if (((from_bitField0_ & 0x00000001) == 0x00000001)) {
          to_bitField0_ |= 0x00000001;
        }
        result.af_ = af_;
        if (((from_bitField0_ & 0x00000002) == 0x00000002)) {
          to_bitField0_ |= 0x00000002;
        }
        result.addr_ = addr_;
        result.bitField0_ = to_bitField0_;
        onBuilt();
        return result;
      }

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

      public Builder mergeFrom(IpAddress.ip_address other) {
        if (other == IpAddress.ip_address.getDefaultInstance()) return this;
        if (other.hasAf()) {
          bitField0_ |= 0x00000001;
          af_ = other.af_;
          onChanged();
        }
        if (other.hasAddr()) {
          bitField0_ |= 0x00000002;
          addr_ = other.addr_;
          onChanged();
        }
        this.mergeUnknownFields(other.getUnknownFields());
        return this;
      }

      public final boolean isInitialized() {
        return true;
      }

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

      private java.lang.Object af_ = "";
      /**
       * <code>optional string af = 1;</code>
       */
      public boolean hasAf() {
        return ((bitField0_ & 0x00000001) == 0x00000001);
      }
      /**
       * <code>optional string af = 1;</code>
       */
      public java.lang.String getAf() {
        java.lang.Object ref = af_;
        if (!(ref instanceof java.lang.String)) {
          com.google.protobuf.ByteString bs =
              (com.google.protobuf.ByteString) ref;
          java.lang.String s = bs.toStringUtf8();
          if (bs.isValidUtf8()) {
            af_ = s;
          }
          return s;
        } else {
          return (java.lang.String) ref;
        }
      }
      /**
       * <code>optional string af = 1;</code>
       */
      public com.google.protobuf.ByteString
          getAfBytes() {
        java.lang.Object ref = af_;
        if (ref instanceof String) {
          com.google.protobuf.ByteString b = 
              com.google.protobuf.ByteString.copyFromUtf8(
                  (java.lang.String) ref);
          af_ = b;
          return b;
        } else {
          return (com.google.protobuf.ByteString) ref;
        }
      }
      /**
       * <code>optional string af = 1;</code>
       */
      public Builder setAf(
          java.lang.String value) {
        if (value == null) {
    throw new NullPointerException();
  }
  bitField0_ |= 0x00000001;
        af_ = value;
        onChanged();
        return this;
      }
      /**
       * <code>optional string af = 1;</code>
       */
      public Builder clearAf() {
        bitField0_ = (bitField0_ & ~0x00000001);
        af_ = getDefaultInstance().getAf();
        onChanged();
        return this;
      }
      /**
       * <code>optional string af = 1;</code>
       */
      public Builder setAfBytes(
          com.google.protobuf.ByteString value) {
        if (value == null) {
    throw new NullPointerException();
  }
  bitField0_ |= 0x00000001;
        af_ = value;
        onChanged();
        return this;
      }

      private java.lang.Object addr_ = "";
      /**
       * <code>optional string addr = 2;</code>
       */
      public boolean hasAddr() {
        return ((bitField0_ & 0x00000002) == 0x00000002);
      }
      /**
       * <code>optional string addr = 2;</code>
       */
      public java.lang.String getAddr() {
        java.lang.Object ref = addr_;
        if (!(ref instanceof java.lang.String)) {
          com.google.protobuf.ByteString bs =
              (com.google.protobuf.ByteString) ref;
          java.lang.String s = bs.toStringUtf8();
          if (bs.isValidUtf8()) {
            addr_ = s;
          }
          return s;
        } else {
          return (java.lang.String) ref;
        }
      }
      /**
       * <code>optional string addr = 2;</code>
       */
      public com.google.protobuf.ByteString
          getAddrBytes() {
        java.lang.Object ref = addr_;
        if (ref instanceof String) {
          com.google.protobuf.ByteString b = 
              com.google.protobuf.ByteString.copyFromUtf8(
                  (java.lang.String) ref);
          addr_ = b;
          return b;
        } else {
          return (com.google.protobuf.ByteString) ref;
        }
      }
      /**
       * <code>optional string addr = 2;</code>
       */
      public Builder setAddr(
          java.lang.String value) {
        if (value == null) {
    throw new NullPointerException();
  }
  bitField0_ |= 0x00000002;
        addr_ = value;
        onChanged();
        return this;
      }
      /**
       * <code>optional string addr = 2;</code>
       */
      public Builder clearAddr() {
        bitField0_ = (bitField0_ & ~0x00000002);
        addr_ = getDefaultInstance().getAddr();
        onChanged();
        return this;
      }
      /**
       * <code>optional string addr = 2;</code>
       */
      public Builder setAddrBytes(
          com.google.protobuf.ByteString value) {
        if (value == null) {
    throw new NullPointerException();
  }
  bitField0_ |= 0x00000002;
        addr_ = value;
        onChanged();
        return this;
      }

      // @@protoc_insertion_point(builder_scope:proto.ip_address)
    }

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

    // @@protoc_insertion_point(class_scope:proto.ip_address)
  }

  private static final com.google.protobuf.Descriptors.Descriptor
    internal_static_proto_ip_address_descriptor;
  private static
    com.google.protobuf.GeneratedMessage.FieldAccessorTable
      internal_static_proto_ip_address_fieldAccessorTable;

  public static com.google.protobuf.Descriptors.FileDescriptor
      getDescriptor() {
    return descriptor;
  }
  private static com.google.protobuf.Descriptors.FileDescriptor
      descriptor;
  static {
    java.lang.String[] descriptorData = {
      "\n\026proto/ip_address.proto\022\005proto\"&\n\nip_ad" +
      "dress\022\n\n\002af\030\001 \001(\t\022\014\n\004addr\030\002 \001(\tB!\n\024com.z" +
      "iyun.bean.protoB\tIpAddress"
    };
    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_proto_ip_address_descriptor =
      getDescriptor().getMessageTypes().get(0);
    internal_static_proto_ip_address_fieldAccessorTable = new
      com.google.protobuf.GeneratedMessage.FieldAccessorTable(
        internal_static_proto_ip_address_descriptor,
        new java.lang.String[] { "Af", "Addr", });
  }

  // @@protoc_insertion_point(outer_class_scope)
}


  • (3)在Java代码中使用上一步编译好的java类
IpAddress.ip_address.Builder builder = IpAddress.ip_address.newBuilder();
builder.setAddr("10.130.254.6");
builder.setAf("af" + String.valueOf(i));
IpAddress.ip_address ipAddress = builder.build();
publisher.send(ipAddress.toByteArray(), ZMQ.NOBLOCK);

语法

与其他语言类型对比

package

.proto文件新增一个可选的package声明符,用来防止不同的消息类型有命名冲突。包的声明符会根据使用语言的不同影响生成的代码。对于C++,产生的类会被包装在C++的命名空间中。

枚举(enum)

enum PhoneType //枚举消息类型
    {
        MOBILE = 0; //proto3版本中,首成员必须为0,成员不应有相同的值
        HOME = 1;
        WORK = 2;
    }

指定字段规则

所指定的消息字段修饰符必须是如下之一:

  • required:一个格式良好的消息一定要含有1个这种字段。表示该值是必须要设置的;
  • optional:消息格式中该字段可以有0个或1个值(不超过1个)。
  • repeated:在一个格式良好的消息中,这种字段可以重复任意多次(包括0次)。重复的值的顺序会被保留。表示该值可以重复,相当于java中的List。
    由于一些历史原因,基本数值类型的repeated的字段并没有被尽可能地高效编码。在新的代码中,用户应该使用特殊选项[packed=true]来保证更高效的编码。如:
    repeated int32 samples = 4 [packed=true];

import

import "myproject/other_protos.proto";

protocol编译器就会在一系列目录中查找需要被导入的文件,这些目录通过protocol编译器的命令行参数-I/–import_path指定。如果不提供参数,编译器就在其调用目录下查找。

protoc命令参数

protoc命令常用法:protoc2.exe -I=./ --java_out=./ ./proto/access_point.proto

protoc参数详解

$ protoc -help 
Usage: protoc [OPTION] PROTO_FILES 
Parse PROTO_FILES and generate output based on the options given: 
  -IPATH, --proto_path=PATH   Specify the directory in which to search for 
                              imports.  May be specified multiple times; 
                              directories will be searched in order.  If not 
                              given, the current working directory is used. 
  --version                   Show version info and exit. 
  -h, --help                  Show this text and exit. 
  --encode=MESSAGE_TYPE       Read a text-format message of the given type 
                              from standard input and write it in binary 
                              to standard output.  The message type must 
                              be defined in PROTO_FILES or their imports. 
  --decode=MESSAGE_TYPE       Read a binary message of the given type from 
                              standard input and write it in text format 
                              to standard output.  The message type must 
                              be defined in PROTO_FILES or their imports. 
  --decode_raw                Read an arbitrary protocol message from 
                              standard input and write the raw tag/value 
                              pairs in text format to standard output.  No 
                              PROTO_FILES should be given when using this 
                              flag. 
  -oFILE,                     Writes a FileDescriptorSet (a protocol buffer, 
    --descriptor_set_out=FILE defined in descriptor.proto) containing all of 
                              the input files to FILE. 
  --include_imports           When using --descriptor_set_out, also include 
                              all dependencies of the input files in the 
                              set, so that the set is self-contained. 
  --include_source_info       When using --descriptor_set_out, do not strip 
                              SourceCodeInfo from the FileDescriptorProto. 
                              This results in vastly larger descriptors that 
                              include information about the original 
                              location of each decl in the source file as 
                              well as surrounding comments. 
  --dependency_out=FILE       Write a dependency output file in the format 
                              expected by make. This writes the transitive 
                              set of input file paths to FILE 
  --error_format=FORMAT       Set the format in which to print errors. 
                              FORMAT may be 'gcc' (the default) or 'msvs' 
                              (Microsoft Visual Studio format). 
  --print_free_field_numbers  Print the free field numbers of the messages 
                              defined in the given proto files. Groups share 
                              the same field number space with the parent 
                              message. Extension ranges are counted as 
                              occupied fields numbers.

  --plugin=EXECUTABLE         Specifies a plugin executable to use. 
                              Normally, protoc searches the PATH for 
                              plugins, but you may specify additional 
                              executables not in the path using this flag. 
                              Additionally, EXECUTABLE may be of the form 
                              NAME=PATH, in which case the given plugin name 
                              is mapped to the given executable even if 
                              the executable's own name differs. 
  --cpp_out=OUT_DIR           Generate C++ header and source. 
  --csharp_out=OUT_DIR        Generate C# source file. 
  --java_out=OUT_DIR          Generate Java source file. 
  --javanano_out=OUT_DIR      Generate Java Nano source file. 
  --js_out=OUT_DIR            Generate JavaScript source. 
  --objc_out=OUT_DIR          Generate Objective C header and source. 
  --python_out=OUT_DIR        Generate Python source file. 
  --ruby_out=OUT_DIR          Generate Ruby source file.

Protobuf 的不足

Protbuf 与 XML 相比也有不足之处。它功能简单,无法用来表示复杂的概念。
XML 已经成为多种行业标准的编写工具,Protobuf 只是 Google 公司内部使用的工具,在通用性上还差很多。
由于文本并不适合用来描述数据结构,所以 Protobuf 也不适合用来对基于文本的标记文档(如 HTML)建模。另外,由于 XML 具有某种程度上的自解释性,它可以被人直接读取编辑,在这一点上 Protobuf 不行,它以二进制的方式存储,除非你有 .proto 定义,否则你没法直接读出 Protobuf 的任何内容。

参考文献


tips:本文属于自己学习和实践过程的记录,很多图和文字都粘贴自网上文章,没有注明引用请包涵!如有任何问题请留言或邮件通知,我会及时回复。

推荐阅读