的详细步骤

作者:澳门新葡京平台游戏

Protobuf是什么?

由于感觉官网上的介绍也比较模糊,所以在自己操作成功后,就把它记录下来.

Google Protocol Buffers是什么

Google Protocol Buffers 简称 Protobuf,它提供了一种灵活、高效、自动序列化结构数据的机制,可以联想 XML,但是比 XML 更小、更快、更简单。仅需要自定义一次你所需的数据格式,然后用户就可以使用 Protobuf 编译器自动生成各种语言的源码,方便的读写用户自定义的格式化的数据。与语言无关,与平台无关,还可以在不破坏原数据格式的基础上,依据老的数据格式,更新现有的数据格式。

Protobuf 的特点简单总结如下几点:

  • 作用与 XML、json 类似,但它是二进制格式,性能好、效率高
  • 代码生成机制,易于使用
  • 解析速度快
  • 支持多种语言
  • 向后兼容、向前兼容
  • 缺点:可读性差

目前,Protobuf 提供了两个大版本: 2.x 版本和 3.x 版本。 2.x 版本最新的版本是 2.6.1,支持 C 、Java 和 Python 三种语言的API。 3.x 版本最新的版本是 3.0.0-beta-1,支持 C 、Java、Python、Ruby、JavaNano、Objective-x 和 C# 这几种语言的 API。

简介

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的优点更明显,它更小、更快、更简单。

Protobuf 即 google protocol buffer 是一种数据封装格式协议,是google推出的一种语言无关、平台无关、扩展性好的用于通信协议、数据存储的结构化数据串行化方法。支持C  、Python、Java三种语言。

Protobuf介绍

官网上介绍的很简单,就是一个Google内部通用的数据交换格式.我们也知道一些数据交换格式,比如,JSON,XML等.

那么为什么Google还要提出Protobuf这种格式呢?因为JSON,XML等格式虽然是对人类非常友好的,但是效率并不高.

简单来说,它就是一种数据交换格式.

Protobuf 如何工作

用户在 .proto 文件中定义 message 来指定所需要序列化的数据格式。每一个 message 都是一个小的信息逻辑单元,包含一系列的 name-value 值对。下面举例来说明一个简单的 .proto 文件,它定义了一条包含 Person 信息的 message

message Person
{
    required string name = 1;
    required int32 id = 2;
    optional string email = 3;

    enum PhoneType
    {
        MOBILE = 0;
        HOME = 1;
        WORK = 2;
    }

    message PhoneNumber
    {
        required string number = 1;
        optional PhoneType type = 2 [default = HOME];
    }

    repeated PhoneNumber phone = 4;
}

从以上代码来看,message 格式非常简单。每种类型的 message 包含一个或者多个唯一编码字段,每个字段由名称和值类型组成,值类型可以是数字(整形或者浮点型)、布尔值、字符串、原始字节,甚至是其他的 message(如上例所示)。Protobuf 允许 message 中包含 message,以达到分层嵌套。message 中可以定义 optional 字段、required 字段和 repeated 字段。

定义好 message 后,运行 Protobuf 编译器编译 .proto 文件,就可以生成存取数据的相关类。这些类包括简单的设置及读取字段(比如 name()set_name() )的方法,也包括整个数据结构的 message 和原始字节之间的序列化/反序列化的转换方法。举个例子,如果你选择的是 C 语言,运行 Protobuf 编译器编译以上 .proto 文件生成 Person 类。你就能使用这个类去填充、序列化、检索 Person message。如下代码:

Person person;
person.set_name("zebra");
person.set_id(123);
person.set_email("zebra@example.com");
fstream output("myfile", ios::out | ios::binary);
person.SerializeToOstream(&output);

接下来,用如下代码来读取 message:

fstream input("myfile", ios::in | ios::binary);
Person person;
person.ParseFromIstream(&input);
cout << "Name: " << person.name() << endl;
cout << "E-mail" << person.email() << endl;

Protobuf 是易于扩展的,可以向后兼容,我们可以在 message 中添加新字段,在解析的时候,老版本的数据就会忽略新增加的字段。因此,如果现有通讯协议使用 Protobuf 做为其数据格式,我们可以直接扩展该通讯协议,而不必担心着将会破坏现有的代码。关于使用 .proto 文件生成目标代码,后面将会介绍。

windows下使用Protobuf

对于非C 用户,可以直接下载官网预编译好的protoc.exe(install the protocol compiler is to download a pre-built binary):

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

为什么要使用Protobuf?

Protobuf编译器安装

由于在使用Protobuf时,是需要我们编写一个proto文件,然后通过一个编译器将其编译成我们需要的格式的文件,比如,对我来说,就要编译成Java格式的文件.

所以,我们需要安装这么一个编译器.

我们来这里下载一个protoc-version-your_platform.zip文件,然后解压并添加到PATH这个环境变量里就行了.

然后安装完成之后,通过protoc --version,能够输出对应的版本,就表示成功了.

如何使用 Protobuf

我们使用 Protobuf 和 C 开发一个简单的例子程序,该程序实现将一些结构化数据写入文件和读取文件。

首先下载 Protobuf 2.6.1 源码。 下载页面:Protobuf github

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 = {
      "n26proto/ip_address.proto2205proto"&nnip_ad"  
      "dress22nn02af3001 01(t2214n04addr3002 01(tB!n24com.z"  
      "iyun.bean.protoBtIpAddress"
    };
    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);
    
在不同平台通信的时候,首先需要将对象进行序列化。iOS平台上我们常用NSKeyedArchiver进行归档,当然也可以将数据处理为JSON或者XML格式。NSKeyedArchiver只能在iOS/Mac平台使用,因此它归档的二进制数据不适合于在不同平台之间使用。JSON和XML虽然由于容易维护,易读而应用比较广泛,但是对数据的利用效率都不是高。这时候该使用Protobuf了,因为Protobuf的优势是效率高,同样的一份数据使用protobuf存储的时候更小,更加方便

Protoc的使用

我们上面说过,我们需要写一个通用的proto文件,然后通过Protoc编译器编译成我们想要的语言的文件,然后再操纵这些文件.

那我们如何来做呢?

首先,我们编写一个proto文件,

syntax = "proto3";

package com.project;

option java_package = "com.projecthome";
option java_multiple_files = true;
option java_outer_classname = "AddressBookProtos";

message Person {

    string name = 1;
    int32 id = 2;
    string email = 3;

    enum PhoneType {
        MOBILE = 0;
        HOME = 1;
        WORK = 2;
    }

    message PhoneNumber {

        string number = 1;
        PhoneType type = 2;

    }

    repeated PhoneNumber phones = 4;

}

message AddressBook {

    repeated Person people = 1;

}

最上面的syntax = "proto3"表示我们这个proto文件的版本,目前有proto2proto3两种版本.

这两种版本的语法,并不完全一样,proto3的比proto2更简洁,你在下载protoc时,也要注意跟这个版本对应.

关于这两种版本的细节,请移步这里

然后,我们可以通过protoc --java_out=${your_output_directory} your_proto_file来编译这个proto文件.我们可以看到,我们编译成的是Java文件.

编译完成后,在${your_output_directory}/com/projecthome下面,可以看到,生成了几个Java文件.

编译安装 Protobuf

Linux用户编译安装如下:

tar -xzf protobuf-2.6.1.tar.gz
cd protobuf-2.6.1
./autogen
./configure --prefix=$INSTALL_DIR
make
make check
make install

如有问题,请认真阅读 protobuf-2.6.1/README.md 和 protobuf-2.6.1/INSTALL.txt。

windows 用户编译安装如下:

  1. 打开 protobuf-2.6.1/vsprojects/protobuf.sln。
  2. 将项目 libprotobuf 设置为启动项目。
  3. 编译 sln,Debug 模式和 Release 模式都编译一下。
  4. 在 vsprojects/Debug 和 vsprojects/Release 目录下会有 libprotobuf.lib、libprotobuf-lite.lib、libprotoc.lib 和 protoc.exe文件。
  5. 新建一个名为 “Install” 的文件夹,在 “Install” 目录下再新建三个文件夹,分别是 “bin”、“include” 和 “lib”。将编译生成的 protoc.exe 拷贝到 “bin” 目录下,将编译生成的 lib 库文件拷贝到 “lib” 目录下,将 protobuf/src 下的源文件拷贝 “include” 目录下。

语法

安装步骤如下:

总结

在这篇文章中,我们介绍了如何安装protoc以及编译proto文件.

关于如何在项目中使用这些编译出的文件,我们会在下一篇文章中介绍.

书写 .proto 文件

定义一个关于个人信息的 .proto 文件,内容如下:

package tutorial;

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

与其他语言类型对比

图片 1

一.安装环境 1.打开终端 2.查看你的mac上是否安装了brew $ brew -v Homebrew 1.6.8 Homebrew/homebrew-core (git revision d822; last commit 2018-06-12) 这是表明已经安装,如果没有安装,使用下面的命令安装下 3.安装brew  $ ruby -e "$(curl -fsSL https://raw.githubusercontent.com/ Homebrew/install/master/install)" 4.下载依赖库 $ brew install automake $ brew install libtool 5.下载Protobuf $ brew install protobuf 6.克隆protobuf-objc,也就是说吧代码下载到本地 $ cd desktop 我是clone到桌面,你们可以随便放那 $ git clone https://github.com/alexeyxo/protobuf-objc.git 7.运行脚本 $ cd ~/protobuf-objc 切换到clone的目录 $ ./scripts/build.sh 或者这样 $ ./autogen.sh $ ./configure $ make # 如果希望安装protoc,执行下面的命令 $ make install 编译后报错:In file included from objc_helpers.cc:27:./google/protobuf/ objectivec-descriptor.pb.h:17:2: error: This file was generated by an older version of protoc which is #error This file was generated by an older version of protoc which is ^ ./google/protobuf/objectivec-descriptor.pb.h:18:2: error: incompatible with your Protocol Buffer headers. Please #error incompatible with your Protocol Buffer headers. Please ^ ./google/protobuf/objectivec-descriptor.pb.h:19:2: error: regenerate this file with a newer version of protoc. #error regenerate this file with a newer version of proton. ......出现这样的错误,不要慌,这是google自己版本的问题,我们不用管他,而且也不会像其他文章说的那样,生成protoc-gen-objc这个插件,根本就不会生成,除非版本是2.6.0,这个问题采用下面的方式一样能生成proto文件
编译 .proto 文件,生成 C 文件

使用 cmd 运行 proto.exe 生成我们的目标语言格式(C )。命令行格式如下:

protoc.exe -I=$SRC_DIR --cpp_out=$DST_DIR $SRC_DIR/person.proto

-I:指定 .proto 文件所在的路径。

--cpp_out:指定生成的目标文件存在的路径。

最后的参数是你需要生成的 .proto 文件名。

上例会生成 person.pb.h 和 person.pb.cc 的文件。person.pb.h 定义了 C 类的头文件,person.pb.cc 是 C 类的实现文件。

package

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

二.生成后缀proto的文件说明: 创建 proto 文件指定数据格式,可以选择proto2和proto3格式,它们有些细微的区别,在生成代码的时候会提示的,具体情况查看文档Language Guide proto3。下面使用proto3格式,并且保存为person.proto。

使用 Protobuf 库提供的 API 来编写应用程序。

使用 Protobuf 库来编写应用程序时,需要包含 Protobuf 的头文件,还需要链接库文件。person.pb.h 头文件定义了设置和读取字段的方法,还有序列化和反序列化的方法,可以很方便的调用,可以参考上一章节的实例。

枚举(enum)

enum PhoneType //枚举消息类型
    {
        MOBILE = 0; //proto3版本中,首成员必须为0,成员不应有相同的值
        HOME = 1;
        WORK = 2;
    }
 1. 创建文件person.proto $ cd desktop 我还是切换到桌面 $ touch person.proto 2. 编辑person.proto文件 2.1 使用终端编辑 $ vi person.proto syntax = "proto3"; message Person{ string name = 1; int32 age = 20; enum DeviceType{ iOS = 0; Android = 1; } } 2.2 放到xcode中直接写

指定字段规则

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

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

三.转化成objc文件

import

import "myproject/other_protos.proto";

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

由于我们生成不了protoc-gen-objc,因此使用protoc --plugin=/usr/local/bin/protoc-gen-objc --objc_out=./ person.proto这种方式是不行的我们使用 protoc 工具生成Objective-C代码:终端输入: $ protoc --proto_path=A --objc_out=B person.proto其中--proto_path=后跟A是需要处理的proto文件所在的文件夹,--objc_out=指明生成的是Objective-C代码以及目标文件存放路径,B是目标文件存放路径,person.proto是需要处理的文件。

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.

这时候我们就生成了2个文件,如下图

Protobuf 的不足

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

图片 2objc-proto文件

参考文献

  • 官网readme
  • Google Protocol Buffer的使用和原理
  • potobuf与JAVA
  • protobuf协议语言指南
  • 在Java中使用Protocol Buffers
  • Protocol Buffer技术详解(Java实例)

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

导入工程中,这两个文件是采用的手动引用计数,因此在加入项目后需要设置它们的编译参数。

图片 3设置

四.项目使用 (下载Protocol Buffers的源码,也可以到官网上下载)

 1.使用cocoapods方式导入 pod 'Protobuf' 而不是 pod 'ProtocolBuffers', 使用 pod 'ProtocolBuffers' 下载成功之后,编译一看,结果报错 #import "GPBProtocolBuffers_RuntimeSupport.h"无法找到

图片 4报错

 原因是pods下来的是不带GPB的,所以网上说的不对,应该是用pod 'Protobuf' ,这样就没有问题 2.静态库引入方式 1.下载Protocol Buffers的源代码 2.工程里引入ProtocolBuffers_iOS.xcodeproj,或者编译成静态库.a方式,然后公开头文件 3.设置依赖和连接库。 4.引入头文件

图片 5图2图片 6图3图片 7图4

参考文章

安装和使用 语法方面 官网教程至于如何使用,下期文章会详细介绍,并提供demo,喜欢的,点下赞,谢谢!

本文由新葡京8455发布,转载请注明来源

关键词: