protobuf详解_protobuf安装

(1) 2024-08-03 10:23

Hi,大家好,我是编程小6,很荣幸遇见你,我把这些年在开发过程中遇到的问题或想法写出来,今天说一说
protobuf详解_protobuf安装,希望能够帮助你!!!。

介绍protobuf之前,先说明一下自定义序列化协议的几个问题。
首先解释一下为什么需要序列化协议而不直接使用类,因为对象中可能有可变字段。

包的分界

为了能让对端知道如何给包分界,意思是,如何区分一帧消息,⽬前⼀般有以下做法:
1. 以固定⼤⼩字节数⽬来分界
例如每个包100个字节,对端每收⻬100个字节,就当成⼀个包来解析。这种方法不灵活,现在基本没有在用了。
2. 以特定符号来分界
例如每个包都以特定的字符来结尾(如\r\n),当在字节流中读取到该字符时,则表明上⼀个包到此为⽌。这种方法总体应用得较少。
3. 固定包头+包体结构
这种结构中⼀般包头部分是⼀个固定字节⻓度的结构,并且包头中会有⼀个特定的字段指定包体的⼤⼩。收包时,先接收固定字节数的头部,解出这个包完整⻓度,按此⻓度接收包体。这是⽬前各种⽹络应⽤⽤的最多的⼀种包格式,即header + body。
4. 在序列化后的buffer前⾯增加⼀个字符流的头部
这个头部中有个字段存储包总⻓度,根据特殊字符(⽐如根据\n或者\0)判断头部的完整性。这样通常⽐方法3要麻烦⼀些,应用的场合较少,HTTP和REDIS采⽤的是这种⽅式。收包的时候,先判断已收到的数据中是否包含结束符,收到结束符后解析包头,解出这个包完整⻓度,按此⻓度接收包体。

包头设计

一是包头中的length字段是否包含头部长度,要约定好。
二是版本号,升级版本号要通过版本号做标识,尽量放在协议头的前面,方便检测版本号,更新版本加的字段都加在版本号最后面。
三是二进制和文本。包头既有二进制形式的,也有文本的。比如二进制header有nginx,文本的header有http。这里注意http的包体既可以是文本的(如html文本),又有二进制形式的(如jpeg)。这里提一下二进制和文本的区别,文本就是经过编码的二进制数据。
四是包头不要序列化。包头主要是用来处理粘包分包等问题,用以区分不同对象,如果包头序列化了,就无法区分不同的序列化对象,因为header都是一样的,就不知道该用哪个反序列化接口。注意包头不需要序列化,包体是需要序列化的。

protobuf使用

protobuf使用较为广泛,tars、grpc、brpc都是用protobuf做的序列化。这里提示一下,protobuf不带加密功能。

接口描述语言

IDL(Interface Descprition Language)接口描述语言。对于protobuf来说,就是.proto文件,然后通过自带的工具,编译生成不同平台不同语言的文件(.cc、.h等)。
package:类似c++的命名空间。

package IM.Message; 

import:引用已经写好了的.proto文件,类似c的include。

import "IM.BaseDefine.proto"; 

message:类似c++的class,注意还可以继续嵌套message。

message IMMsgDataAck{ //cmd id: 0x0302 uint32 user_id = 1; //发送此信令的用户id uint32 session_id = 2; uint32 msg_id = 3; IM.BaseDefine.SessionType session_type = 4; } 

上面的1,2,3,4不是初始值,是序号,为压缩做准备,是field_num。

编译proto

将proto⽂件⽣成对应的.cc和.h⽂件

protoc -I=/路径1 --cpp_out=./路径2 /路径1/addressbook.proto 

路径1为.proto所在的路径,路径2为.cc和.h⽣成的位置。
生成.cc文件后,再使用g++编译,注意链接库,c++11等。

编码原理

protobuf采⽤Varints编码和Zigzag编码来编码数据,编码格式是field_num+wire type(+len)+value。当wire type为2时,会增加一个len字段。这里只做简单介绍。
Varints编码
1.不需要记录高位的0。
2.采用Base128编码。1个字节只表示128大小,即数据位只占7bit。最高位是最后一个字节为0,其余字节为1。
3.高位在后,低位在前。
4.field_num。14位表示,第0位是0(Base128),57位表示wire type。4bit只能表示到15,超过15就需要两个字节。
5.负数。如果是负数,则恒定用10+1字节表示:补码int32->uint64->10B,注意低位在前。
可以用sint32或sint64表示负数(Varints编码和Zigzag编码组合),编码速度会慢一些。
Zigzag编码
Zigzag编码的目的在于把高位的1变成0。这里不再详细介绍。
fixed32
对于fixed32、fixed64等变量,由于长度固定,就没有使用Base128编码。
最后再提示一下,注意序列化、反序列化是支持不同的接口的,保存到网络或本地都是可以的。
当然,序列化协议不一定非要用protobuf,即时通讯和聊天消息用protobuf较多,而web中注册账号用的是json。这里补充一下,http中api是通过url来区分不同的json对象进行反序列化的。

今天的分享到此就结束了,感谢您的阅读,如果确实帮到您,您可以动动手指转发给其他人。

上一篇

已是最后文章

下一篇

已是最新文章

发表回复