Protobuf全称Protocol Buffers,简称GPB、PB。
- 是 Google 的语言中立、平台中立、可扩展的结构化数据序列化机制
- xcode环境变量
- 推导解析:拿到第一个Tag,解析出它的
fieldNumber
和wireType
,因为采用varint
编码方式,高位为1表示下一字节还是该数字,为0刚表示下一个字节是下一个Tag
。如果一开始传输的是一个字符串,那么下一个字节就开始解析Length
,Length
同样用的是varint
编码,遇到0后表示该Length
解析完后,我们就能拿到value
的长度,接下来按照长度取完字符串后。下一个字节就是Tag
了。以此类推protobuf
永远知道哪一个字节是Tag
。
文章
思路
- 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);
- 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
结果一样
断点调试
- 第一个字节是由
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)
-
后面字节依此类推
-
第一字节换算方式
tag = (fileNumeer << 3) | wireType
wireType = tag & 0b111
- 关键技术
- wiretype 0 1固定64位 5固定32位 2 t-l-v
- 负数使用zigzag编码
- repeated编码 TLVVV...编码