之间已经介绍了Protobuf的安装,最近使用了一下protobuf进行服务器与客户端的使用,发现protobuf确实很方便。
简单的protobuf的用法教程网上已经很多了,这里先简单的总结一下:
1,首先写proto文件,这里以官方教程为例
package tutorial; //命名空间,对应C++中的 namespace tutorial
message Person {
required string name = 1; //protobuf 有自己定义的各种数据类型,对应各种语言不同的数据类型
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 PhoneNumber 只是对变量的声明,可以从后面跟着的变量ID看出来,其中repeated关键字代表数组的意思
}
// Our address book file is just one of these.
message AddressBook {
repeated Person person = 1; //这里就是消息的内嵌了,AddressBook中的变量类型是之前声明的Person类型
}
写好proto文件就可以进行编译了,编译的方法如下,上面的proto文件名为 addressBook.proto
protoc --cpp_out=. addressBook.proto // --cpp_out代表生成的C++代码
这样就会生成 addressBook.pb.h 和 addressBook.pb.cc 两个文件,就可以直接使用这两个文件了。使用proto文件主要是两个问题,一个是怎么发送和接收,另一个是怎么赋值和读取数据。
先谈第一个问题,怎么接收和发送,网络传输传输的都是字节流,因此要把需要发送的数据序列化,把收到的数据进行反序列化,这可以通过protobuf提供的API来实现;第二个问题,怎么对协议进行赋值和读取数据,生成的类文件中提供了相应的方法,针对上面的例子,可以看一下具体的操作
1、C数组的序列化和反序列化API
//C数组的序列化和序列化API
bool ParseFromArray(const void* data, int size);
bool SerializeToArray(void* data, int size) const;
//使用
void set_people()
{
wp.set_name("sealyao"); //用来赋值的函数
wp.set_id(123456);
wp.set_email("sealyaog@gmail.com");
wp.SerializeToArray(parray,256);
}
void get_people()
{
rap.ParseFromArray(parray,256);
cout << "Get People from Array:" << endl;
cout << "\t Name : " <<rap.name() << endl; //用来读取变量的函数
cout << "\t Id : " << rap.id() << endl;
cout << "\t email : " << rap.email() << endl;
}
2、C++ String的序列化和反序列化API
//C++string序列化和序列化API
bool SerializeToString(string* output) const;
bool ParseFromString(const string& data);
//使用:
void set_people()
{
wp.set_name("sealyao");
wp.set_id(123456);
wp.set_email("sealyaog@gmail.com");
wp.SerializeToString(&pstring);
}
void get_people()
{
rsp.ParseFromString(pstring);
cout << "Get People from String:" << endl;
cout << "\t Name : " <<rsp.name() << endl;
cout << "\t Id : " << rsp.id() << endl;
cout << "\t email : " << rsp.email() << endl;
}
3、文件描述符序列化和反序列化API
//文件描述符的序列化和序列化API
bool SerializeToFileDescriptor(int file_descriptor) const;
bool ParseFromFileDescriptor(int file_descriptor);
//使用:
void set_people()
{
fd = open(path,O_CREAT|O_TRUNC|O_RDWR,0644);
if(fd <= 0){
perror("open");
exit(0);
}
wp.set_name("sealyaog");
wp.set_id(123456);
wp.set_email("sealyaog@gmail.com");
wp.SerializeToFileDescriptor(fd);
close(fd);
}
void get_people()
{
fd = open(path,O_RDONLY);
if(fd <= 0){
perror("open");
exit(0);
}
rp.ParseFromFileDescriptor(fd);
std::cout << "Get People from FD:" << endl;
std::cout << "\t Name : " <<rp.name() << endl;
std::cout << "\t Id : " << rp.id() << endl;
std::cout << "\t email : " << rp.email() << endl;
close(fd);
}
4、C++ stream 序列化和反序列化API
//C++ stream 序列化/反序列化API
bool SerializeToOstream(ostream* output) const;
bool ParseFromIstream(istream* input);
//使用:
void set_people()
{
fstream fs(path,ios::out|ios::trunc|ios::binary);
wp.set_name("sealyaog");
wp.set_id(123456);
wp.set_email("sealyaog@gmail.com");
wp.SerializeToOstream(&fs);
fs.close();
fs.clear();
}
void get_people()
{
fstream fs(path,ios::in|ios::binary);
rp.ParseFromIstream(&fs);
std::cout << "\t Name : " <<rp.name() << endl;
std::cout << "\t Id : " << rp.id() << endl;
std::cout << "\t email : " << rp.email() << endl;
fs.close();
fs.clear();
}