ZigZag算法
ZigZag好处就是进行负数变换,原本负数首位为1导致的Varint编码无效,利用ZigZag技术就可以进行编码了
源码
第一位的1和0代表负和正
[+8] = [00001000]原
[-8] = [10001000]原
反码
第一位为0不变,第一位为负的话,他的其余位全部取反
[+8] = [00001000]原 = [0000 1000]反
[-8] = [10001000]原 = [1111 0111]反
补码
第一位为正不进行补偿,第一位为负最后一位加1
[+8] = [00001000]原 = [0000 1000]补
[-8] = [10001000]原 = [1111 0111]反 = [1111 1000]补
ZigZag
正数 0000 1000
- 数据左移一位:
0001 0000 - 符号位(正数的符号为0)放到最后一位:
0001 0000
负数 1111 1000
- 左移一位:
1111 0000 - 符号位放到最后一位:
1111 0001 - 除最后一位外全部取反:
0000 1111
Varint编码
Varint编码后的数字,每次进行解码的时候就可以没8位的首位进行判定该字节是否到头,然后就可以紧凑的编码了
十进制300, 二进 00|00 0001 0|010 1100
- 从右到左没7位截取,后面还是该数字的一部分就填充1,到这里终止了就填充0,然后从左往右排
- 右边7位 = 010 1100 = 1010 1100
- 左边7位 = 00 0001 0 = 10
- 最终 10 1010 1100
Message Buffer
- keyvalue|keyvalue 紧凑型排列
- key定义
(field_number << 3) | wire_type - field_number就是.proto中属性的数字,wire_type就是类型如下图

proto实现原理
在执行protoc编译的时候,命令行是这样写的:protoc -go_out=./ *.proto,Protobuf原生支持go所以认识-go_out,这表示把当前目录下所有proto都编译成go。如果我们命令行这样写:protoc -xxx_out=./ *.proto,由于不认识xxx,于是protoc会在PATH路径下寻找一个叫做protoc-gen-xxx的可执行文件。而protoc-gen-xxx就是我们要实现的插件
对比go的插件实现
代码都是生成的,只是两种形式,一种是用generator的plugin来进行调用,一种是直接调用grpc来生成代码,但是都要使用generator来生成protobuf,因为要生成基本的数据结构,后续的grpc自行实现
生成的命令
protoc --netrpc_out=plugins=netrpc:. hello.proto
假如你生成的插件叫netrpc,那你的.exe文件就要叫做protoc-gen-netrpc, 这样protoc就会调用你的插件进行生成代码了
个人思考
代码生成本质就是使用一定的信息,根据模板生成固定的信息,像存前端使用前端的模板技术通过网页和js直接生成grpc和protobuf,像我经常就用layui的模板生成crud的代码,到这里说实话protobuf的字节码的编码和解码技术还是可以的,生成代码没啥东西