ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

protobuf和grpc

2022-06-26 00:31:34  阅读:210  来源: 互联网

标签:编码 protobuf Varints 16 grpc Zigzag


一、grpc安装

  在安装之前确保已经安装好了c/c++的编译环境(指令:sudo apt install -y build-essential autoconf libtool pkg-config)以及cmake、openssl等工具。

  (1)下载grpc

git clone https://github.com/grpc/grpc.git
cd grpc
git submodule update --init

  (2)编译安装protobuf

cd third_party/protobuf/
git submodule update --init --recursive
./autogen.sh
./configure
make -j8
sudo make install
sudo ldconfig

  (3)编译安装grpc

cd grpc
mkdir -p cmake/build
cd cmake/build
cmake ../..
make -j8
sudo make install

  (4)编译example

cd grpc/examples/cpp/helloworld
cmake ../..
make -j8
#启动服务端
./greeter_server
#启动客户端
./greeter_client

二、protobuf编码原理

  (1)Varints编码

   Varints编码使用每个字节的最高有效位做为标志位,而剩余的7位以二进制补码的形式来存储数字值本身,当最高有效位为1时,代表其后面还跟有字节,当最高有效位为0时,代表已经是该数字的最后一子节,在protobuf中,使用的是Base128 Varints编码,之所以这么称呼,是因为使用7bit来存储数字,在protobuf中,Base128 Varints采用的是小端序,即数字的低位存放在高位地址,

十进制:127
二进制:111 1111
Varints:0111 1111 (最高位0,表示没有后续byte) ----> 16进制: 0x7f

十进制:128
二进制(7bit分隔): 1|000 0000
Varints:
	① 取最低的7bit: 1000 0000 (最高位1,表示有后续byte)----> 16进制: 0x80
	② 剩余的1bit,不足补0: 0000 0001  (最高位0,表示没有后续byte)----> 16进制: 0x01
	③ 小端存储:0x80,0x01
	
十进制:16385
二进制(7bit分隔):1|000 0000|000 0001
Varints:
	① 取最低的7bit: 1000 0001 (最高位1,表示有后续byte)----> 16进制: 0x81
	② 中间7bit: 1000 0000 (最高位1,表示有后续byte)----> 16进制: 0x80
	③ 剩余的1bit: 0000 0001 (最高位0,表示没有后续byte)----> 16进制: 0x01
	③ 小端存储:0x81,0x80,0x01

  (2)Zigzag编码

  Zigzag 编码的大致思想是首先对负数做一次变换, 将其映射为一个正数, 变换以后便可以使用 Varints 编码进行压缩, 这里关键的一点在于变换的算法, 首先算法必须是可逆的, 即可以根据变换后的值计算出原始值, 否则就无法解码, 同时要求变换算法要尽可能简单, 以避免影响 Protobuf 编码、解码的速度;则 Zigzag 编码的计算方式为:

(n << 1) ^ (n >> 31)

  左边是逻辑移位, 右边是算术移位, 右边的含义实际是得到⼀个全 1 (对于负数) 或全 0(对于正数)的⽐特序列。

  假设数字为 -5, 其在内存中的形式为:    

  ⾸先对其进⾏⼀次逻辑左移, 移位后空出的⽐特位由 0 填充。           

   然后对原数字进⾏ 15 次算术右移, 得到 16 位全为原符号位(即 1)的数字。

   然后对逻辑移位和算术移位的结果按位异或, 便得到最终的 Zigzag 编码。

  可以看到,对于负数使用Zigzag编码以后,其高位的1全部变为0,这样便可以使用Varints编码进一步压缩,再来看正数的情况,对于16位的正数5,其在内存中的存储形式为:

   按照与负数相同的处理方法,可以得到其Zigzag编码为:

   从上⾯的结果来看, ⽆论是正数还是负数, 经过 Zigzag 编码以后, 数字⾼位都是 0, 这样以来,便可以进⼀步使⽤ Varints 编码进⾏数据压缩,即 Zigzag 编码在 Protobuf 中并不单独使⽤, ⽽是配合Varints 编码共同来进⾏数据压缩。

  注意事项:

  (a)当字段可能为负数时, 我们应使⽤ sint32 或 sint64, 这样Protobuf 会按照 Zigzag 编码将数据变换后再采⽤ Varints 编码进⾏压缩,从⽽缩短数据的⼆进制位数;

  (b)protobuf不是完全自描述的信息格式,接收端需要有相应的解码器(即proto定义)才可以解析数据格式,序列化后的protobuf数据不携带字段名,只使用字段编号来标识一个字段,因此更改proto的字段名不会影响数据的解析,字段编号会被编码进二进制的消息结构中,因此尽可能地使用小的编号;

  (c)protobuf是一种紧密的消息结构,编码后字段之间没有间隔,每个字段头由两部分组成:字段编号和wire type,字段头可确定数据段的长度,因此其字段之前无需加间隔,也无需引入特定的数据来标记字段末尾,因此protobuf的编码长度短,传输效率高;

  (d)如果添加新字段,客户端使用了新的代码,服务端依然可以使用旧的二进制在解析,只是会简单地忽略新添加字段。

三、protobuf的使用

  (1)数值类型

    一个标量消息字段可以含有一个如下的类型

  (2)定义一个消息类型:

syntax = "proto3";
message SearchRequest { 
    string query = 1; 
    int32 page_number = 2; 
    int32 result_per_page = 3; 
}

  在消息定义中,每个字段都有唯一的一个数字标识符,这个标识符是用来在消息的二进制格式中识别各个字段的,一旦开始使用不能够再改变,范围[1,2^29-1]

  (3)枚举的使用

 message SearchRequest { 
    string query = 1; 
    int32 page_number = 2;
    int32 result_per_page = 3; 
    enum Corpus { 
        UNIVERSAL = 0; //从0开始
        WEB = 1; 
        IMAGES = 2;
        LOCAL = 3; 
        NEWS = 4; 
        PRODUCTS = 5; 
        VIDEO = 6; 
    }
    Corpus corpus = 4; 
}            

 (4)服务定义

    如果将消息用在rpc远程方法调用,可以在proto文件中定义一个rpc服务接口,该方法接收参数helloRequest,返回一个helloResponse。

service myService{

  rpc  Hello(helloRequest) returns (helloResponse) ;

}

 

标签:编码,protobuf,Varints,16,grpc,Zigzag
来源: https://www.cnblogs.com/juju-go/p/16406109.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有