欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 教育 > 培训 > protobuf: 网络版通讯录

protobuf: 网络版通讯录

2025/10/14 5:24:40 来源:https://blog.csdn.net/yiren_liusong/article/details/145246569  浏览:    关键词:protobuf: 网络版通讯录

1.客户端

1.协议约定

2..proto文件编写

syntax = "proto3";
package Add_http_contacts;message AddContactRequest
{string name = 1;int32 age = 2;//里面是电话的字段和类型message Phone{string num = 1;enum PhoneType {MP = 0; // 移动电话TEL = 1; // 固定电话}PhoneType type = 2;}repeated Phone phone = 3;
}message AddContactResponse
{bool success = 1;string error_desc = 2;string uuid = 3;
}

3.Makefile

server:*.ccg++ -o $@ $^ -std=c++11 -lpthread -lprotobuf    //-lpthread是因为引入了第三方 httplib库
.PHONY:clean
clean:rm -rf server

4.异常类

#include <iostream>
#include <string>class ContactException
{
private:std::string _error;
public:ContactException(std::string err = "a problem"):_error(err){}std::string What() const{return _error;}
};

5.client.cc

#include <iostream>
#include "httplib.h"
#include "ContactException.hpp"
#include "add_contact.pb.h"using std::cerr;
using std::cin;
using std::cout;
using std::endl;using namespace httplib;#define CONTACT_HOST "82.157.3.118"
#define CONTACT_PORT 8888void menu()
{std::cout << "-----------------------------------------------------" << std::endl<< "--------------- 请选择对通讯录的操作 ----------------" << std::endl<< "------------------ 1、新增联系⼈ --------------------" << std::endl<< "------------------ 2、删除联系⼈ --------------------" << std::endl<< "------------------ 3、查看联系⼈列表 ----------------" << std::endl<< "------------------ 4、查看联系⼈详细信息 ------------" << std::endl<< "------------------ 0、退出 --------------------------" << std::endl<< "-----------------------------------------------------" << std::endl;
}void BuildAddContactRequest(Add_http_contacts::AddContactRequest *req)
{std::cout << "--------------新增联系人--------------" << std::endl;std::cout << "请输入联系人的姓名: ";std::string name;getline(std::cin, name);req->set_name(name);std::cout << "请输入联系人的年龄: ";int age;std::cin >> age;req->set_age(age);std::cin.ignore(256, '\n'); // 清除缓冲区所有内容,直到'\n',把'\n'删除后结束,或者清除256个字节直接结束for (int i = 0;; i++){std::cout << "请输入联系人的电话: " << i + 1 << "(只输入回车完成电话新增): ";std::string number;getline(std::cin, number);if (number.empty())break;// 接收add_phone返回的phone对象Add_http_contacts::AddContactRequest_Phone *phone = req->add_phone();phone->set_num(number);std::cout << "请输入联系人的电话类型:(0.移动电话, 1.固定电话): ";int type;std::cin >> type;std::cin.ignore(256, '\n');switch (type){case 0:phone->set_type(Add_http_contacts::AddContactRequest_Phone_PhoneType::AddContactRequest_Phone_PhoneType_MP);break;case 1:phone->set_type(Add_http_contacts::AddContactRequest_Phone_PhoneType::AddContactRequest_Phone_PhoneType_TEL);break;default:std::cout << "输入有误, 请重新根据提示输入" << std::endl;break;}}
}
void AddContact()
{Client client(CONTACT_HOST, CONTACT_PORT);// 构建req对象Add_http_contacts::AddContactRequest req;BuildAddContactRequest(&req);// 序列化std::string req_str;if (!req.SerializeToString(&req_str)){std::string errstr = "AddContact时,序列化失败";throw ContactException(errstr);}// 发起post请求auto post = client.Post("/contacts/add", req_str, "application/protobuf");if (!post) {std::string err_str = "/contacts/add 链接失败,错误原因: ";err_str.append(httplib::to_string(post.error()));throw ContactException(err_str);}// 反序列化rspAdd_http_contacts::AddContactResponse resp;bool parse = resp.ParseFromString(post->body);if (post->status != 200 && !parse){std::string err_str = "调用 /contact/add 失败 ";err_str.append(std::to_string(post->status)).append("(").append(post->reason).append(")");throw ContactException(err_str);}else if (post->status != 200){std::string err_str = "调用 /contact/add 失败 ";err_str.append(std::to_string(post->status)).append("(").append(post->reason).append(")").append("错误原因: ").append(resp.error_desc());throw ContactException(err_str);}else if (!resp.success()){std::string err_str = "调用 /contact/add 结果异常 ";err_str.append("异常原因: ").append(resp.error_desc());throw ContactException(err_str);}// 打印结果cout << "新增联系人成功" << "联系人id: " << resp.uuid() << endl;
}int main()
{enum Option{Quit = 0,Add,Del,Findone,Findall};menu();cout << "---->请选择: ";int choose;cin >> choose;cin.ignore(256, '\n');try{switch (choose){case Option::Quit:cout << "---->退出" << endl;return 1;case Option::Add:cout << "---->新增联系人" << endl;AddContact();break;case Option::Del:cout << "---->暂未实现" << endl;break;case Option::Findone:cout << "---->暂未实现" << endl;break;case Option::Findall:cout << "---->暂未实现" << endl;break;default:cout << "---->选择有误,请重新选择" << endl;break;};}catch (const ContactException &e){cout << "--->出现错误, 错误原因是: " << e.What() << endl;}
}

2.服务端

1.UUIDUtil类

#pragma once
#include <iostream>
#include <sstream>
#include <string>
#include <random>
#include <iomanip>
#include <atomic>namespace ns_uuid
{class UUIDUtil{public:static std::string uuid(){// 生成机器随机数对象std::random_device rd;// 用mt算法,以机器随机数对象为种子生成伪随机数对象std::mt19937 generator(rd());// 构造限定数据范围的伪随机数std::uniform_int_distribution<int> distribution(0, 255);// ⽣成8个随机数,按照特定格式组织成为16进制数字字符的字符串std::stringstream ss;for (int i = 0; i < 8; i++){if(i == 4 || i == 6) ss << "-";ss << std::setw(2) << std::setfill('0') << std::hex << distribution(generator);}ss << "-";// 定义⼀个8字节序号,逐字节组织成为16进制数字字符的字符串static std::atomic<int> a(0);// size_t 64个bit位size_t cur = a.fetch_add(1);for (int i = 7; i >= 0; i--){if(i == 5) ss << "-";ss << std::setw(2) << std::setfill('0') << std::hex << ((cur >> (i*8)) & 0xFF);}return ss.str();}};
}

2.server.cc

#include <iostream>
#include "add_contact.pb.h"
#include "ContactException.hpp"
#include <string>
#include "httplib.h"
#include "UUIDUtil.hpp"using namespace httplib;
using namespace ns_uuid;
using std::cout;
using std::endl;void PrintContacts(Add_http_contacts::AddContactRequest& request)
{std::cout << "联系人姓名:" << request.name() << std::endl;std::cout << "联系人年龄:" << request.age() << std::endl;for(int j = 0;j<request.phone_size();j++){const Add_http_contacts::AddContactRequest_Phone phone = request.phone(j);std::cout << "联系人电话" << j+1  << ": "<< phone.num() << "   ";std::cout << "电话类型"  << ": ("<< AddContactRequest_Phone_PhoneType_Name(phone.type()) << ")" << std::endl; }
}
int main()
{Server server;server.Post("/contacts/add", [](const Request &req, Response &resp){// 反序列化request : req.bodyAdd_http_contacts::AddContactRequest request;Add_http_contacts::AddContactResponse response;try{if (!request.ParseFromString(req.body)){throw ContactException("request反序列化失败");}//新增联系人,持久化存储——————这里只是实现打印PrintContacts(request);// 序列化responseresponse.set_success(true);response.set_uuid(UUIDUtil::uuid());std::string resp_str;if (!response.SerializeToString(&resp_str)){throw ContactException("response序列化失败");}resp.status = 200;resp.body = resp_str;resp.set_header("Content-Type", "application/protobuf");}catch (const ContactException &e){resp.status = 500;response.set_success(false);response.set_error_desc(e.What());std::string resp_str;if (response.SerializeToString(&resp_str)){resp.body = resp_str;resp.set_header("Content-Type", "application/protobuf");}}});server.listen("0.0.0.0", 8888);return 0;
}

3.总结

序列化协议

通⽤性

格式

可读性

序列化⼤

序列化性能

JSON

通⽤(json、

xml已成为多种

⾏业标准的编

写⼯具

⽂本格式

轻量(使

⽤键值对

⽅式,压

缩了⼀定

的数据空

XML

通用

⽂本格式

重量(数

据冗余,

因为需要

成对的闭

合标签

ProtoBuf

独⽴

(Protobuf只

是Google公司

内部的⼯具)

⼆进制格式

差(只能

反序列化

后得到真

正可读的

数据)

轻量(⽐

JSON更轻

量,传输

起来带宽

和速度会

有优化

⼩结:
  1. XML、JSON、ProtoBuf都具有数据结构化和数据序列化的能⼒。
  2. XML、JSON更注重数据结构化,关注可读性和语义表达能⼒。ProtoBuf更注重数据序列化,关注
效率、空间、速度,可读性差,语义表达能⼒不⾜,为保证极致的效率,会舍弃⼀部分元信息。
3. ProtoBuf的应⽤ 场景更为明确,XML、JSON的应⽤ 场景更为丰富。
protobuf 和 Json 的实验对比:
  • 编解码性能:ProtoBuf的编码解码性能,⽐JSON⾼出2-4倍。
  • 内存占⽤:ProtoBuf的内存278,⽽JSON到达567,ProtoBuf的内存占⽤只有JSON的1/2。
注:以上结论的数据只是根据该项实验得出。因为受不同的字段类型、字段个数等影响,测出的数据会有所差异。

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

热搜词