Protocol Buffers

Protobuf全称Protocol Buffers,简称GPB、PB。

  • 是 Google 的语言中立、平台中立、可扩展的结构化数据序列化机制
  • xcode环境变量
  • 推导解析:拿到第一个Tag,解析出它的fieldNumberwireType,因为采用varint编码方式,高位为1表示下一字节还是该数字,为0刚表示下一个字节是下一个Tag。如果一开始传输的是一个字符串,那么下一个字节就开始解析LengthLength同样用的是varint编码,遇到0后表示该Length解析完后,我们就能拿到value的长度,接下来按照长度取完字符串后。下一个字节就是Tag了。以此类推protobuf永远知道哪一个字节是Tag

文章

思路

  1. oc项目 ~/Github/protobuf_cpp,NSData.bytes
    UserInfo *userinfo = [[UserInfo alloc] init];
    userinfo.key1 = 123;
    userinfo.key3  = @"liangze";
    userinfo.key2 = @"https://baidu.com";
    NSData *data = userinfo.data;
    NSLog(@"xptod %p -c 0x%x", data.bytes, data.length);
    
  1. swift项目 ~/Github/protobuf_swift
var user = UserInfo()
        user.key1 = 123
        user.key2 = "liangze"
        user.key3 = "https://baidu.com"
        
        if let data = try? user.serializedData(), let d2 = try? user.serializedData(partial: true) {
            data.withUnsafeBytes { pointer in
                let user2 = try! UserInfo(contiguousBytes: pointer)
                print(pointer)
            }
            print("")
        }
▿ _position : Optional<UnsafeRawPointer>
    ▿ some : 0x0000000280e42f40
      - pointerValue : 10752372544
  ▿ _end : Optional<UnsafeRawPointer>
    ▿ some : 0x0000000280e42f5e
      - pointerValue : 10752372574

xptod %p -c 0x%x 结果一样

断点调试

image.png

  1. 第一个字节是由fieldNumber ( = 1 2 3...)WireFormat (WireFormat.varint)组成
//struct FieldTag
init(fieldNumber: Int, wireFormat: WireFormat) {
    self.rawValue = UInt32(truncatingIfNeeded: fieldNumber) << 3 |
      UInt32(wireFormat.rawValue)
  }

case varint = 0
  case fixed64 = 1
  case lengthDelimited = 2
  case startGroup = 3
  case endGroup = 4
  case fixed32 = 5
FieldTag(fieldNumber: fieldNumber, wireFormat: wireFormat)
  1. 后面字节依此类推
    image.png

  2. 第一字节换算方式

tag = (fileNumeer << 3) | wireType 
wireType = tag & 0b111
  • 关键技术
  1. wiretype 0 1固定64位 5固定32位 2 t-l-v
  2. 负数使用zigzag编码
  3. repeated编码 TLVVV...编码