protocol buffer 的使用(一)

1、什么是Protocol buffer

Protocol buffer是由Geogle开发的通用通信协议,一种语言无关、平台无关、扩展性好的用于通信协议、数据存储的结构化数据序列化方法。

2、protocol buffer的使用及数据类型介绍

protocol buffer(下面介绍时,统称为p_b)在使用上,有些像c语言的结构体,声明结构体名称及结构体内部的相关变量。 下面通过一个示例,来了解p_b的相关结构体定义及其类型

message Person {
  required string name = 1;
  required int32 id = 2;
  optional string email = 3;
 
  enum PhoneType {
    MOBILE = 0;
    HOME = 1;
    WORK = 2;
  }
 
  message PhoneNumber {
    required string number = 1;
    optional PhoneType type = 2 [default = HOME];
  }
 
  repeated PhoneNumber phone = 4;

message

定义一个消息数据的名称,相当于struct中的结构体名称

required

我理解这属于一个属性字段,设置为required的字段,必须要被用户使用

optional

同上,一个属性字段,设置该属性字段后,读取message数据的一方可以选择读取该字段,也可以不对,并不做强制要求。

enum

枚举,其最用与c语言中的枚举时相同的用法

repeated

可重复(变长)字段,设置了该属性的字段,我们可以将其理解为定义的一个数组

上面主要为一些portocol的相关属性字段设置,下面的表格则是关于变量类型定义时的数据类型字段

protocol类型C++类型
doubledouble
floatfloat
boolbool
stringstring
bytesstring

其中还有四个类型与c语言的有区别

protocol类型C++类型补充
int32int32Uses variable-length encoding. Inefficient for encoding negative numbers – if your field is likely to have negative values, use sint32 instead.
int64int64Uses variable-length encoding. Inefficient for encoding negative numbers – if your field is likely to have negative values, use sint64 instead.
uint32uint32Uses variable-length encoding.
uint64uint64Uses variable-length encoding.
sint32int32Uses variable-length encoding. Signed int value. These more efficiently encode negative numbers than regular int32s.
sint64int64Uses variable-length encoding. Signed int value. These more efficiently encode negative numbers than regular int64s.
fixed32uint32Always four bytes. More efficient than uint32 if values are often greater than 228.
fixed64uint64Always eight bytes. More efficient than uint64 if values are often greater than 256.
sfixed32int32Always four bytes.
sfixed64int64Always eight bytes.

3、示例

下面利用protocol buffer生成一个消息类,并在程序中使用

a. 编写一个.prob文件,命名为lm.hello.prob

package lm;
message helloworld 
{ 
   required int32     id = 1;  // ID 
   required string    str = 2;  // str 
   optional int32     opt = 3;  //optional field 
}

将其编译输出为cpp类型文件

protoc lm.hello.proto --cpp_out=./

b. 编写一个cpp程序来使用这个message类

这里会写一个write基于message写入文件,再写一个read基于message来读取文件

  • write.cpp
#include<iostream>
#include<fstream>
#include"lm.hello.pb.h"
int main()
{
  lm::helloworld msg1;
  msg1.set_id(101);
  msg1.set_str("hello");
  msg1.add_nums(1);
  msg1.add_nums(2);
  std::fstream output("./log",std::ios::out|std::ios::trunc |std::ios::binary);
  if(!msg1.SerializeToOstream(&output)){
    std::cout<<"Failed to write msg"<<std::endl;
    return -1;
  }
  return 0;
}

  • read.cpp
#include<iostream>
#include<fstream>
#include"lm.hello.pb.h"
void ListMsg(const lm::helloworld &msg){
	std::cout<<msg.id()<<std::endl;
	std::cout<<msg.str()<<std::endl;
	for(int i =0;i<msg.nums_size();i++)
	std::cout<<msg.nums(i)<<std::endl;

}
int main(){
	lm::helloworld msg1;
	std::fstream input("./log",std::ios::in|std::ios::binary);
	if(!msg1.ParseFromIstream(&input)){
		std::cout<<"Failed to parse address book"<<std::endl;
		return -1;
	}
	ListMsg(msg1);
}

c. 进行编译

g++ write.cpp lm.hello.pb.cc lm.hello.pb.h -o write -lprotobuf
g++ read.cpp lm.hello.pb.cc lm.hello.pb.h -o read -lprotobuf

d. 执行及结果显示

root@fafZ:~/WorkCode/Protocol/code# clear
root@fafZ:~/WorkCode/Protocol/code# ./write 
root@fafZ:~/WorkCode/Protocol/code# ./read 
101
hello
1
2

4、Protocol buffer的相关api介绍

先通过上面的例子来对Protocol buffer进行介绍

下面在介绍相关接口,都是基于message变量已设置

set_字段名()

//写入
messgae.set_id(5);  //给message中的id字段赋值
//读取
message.id();  //直接从message中读取数据

add_字段名()

//写入
message.add_nums(1);
message.add_nums(2);

//读取
for(int i=0;i<message.nums_size();i++){
    std::cout<<"message.num"<<i<<":"<<message.nums(i);
}

add主要是针对repeated属性的字段进行数值的添加,同时对repeated数据的访问也是需要对应下标去访问

SerializeToOstream(ostream* output) const 和 ParseFromIstream(istream* input)

std::fstream output("./log",std::ios::out|std::ios::trunc |std::ios::binary);
msg1.SerializeToOstream(&output);
std::fstream input("./log",std::ios::in|std::ios::binary);
msg1.ParseFromIstream(&input);

该接口会将msg1中设置的数据都进行序列化操作,保存在对应的文件流中

SerializeToString(string* output) const 和 ParseFromString(const string& data)

std::string str;
obj.SerializeToString(&str);
obj2.ParseFromString(str);

与上面接口相似,只是该接口会把message中的数据存放在字符串类型中,再反序列化时,需要用到对应的string对象。

其他

当我们在程序中要对相关字段进行操作时,一般可以打开生成的.h文件,里面可以查看对应字段.proto提供给我们的接口。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值