news 2026/7/7 19:46:48

三.网络版通讯录

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
三.网络版通讯录

一.回顾

上篇博客链接:

https://blog.csdn.net/weixin_60668256/article/details/155931223?fromshare=blogdetail&sharetype=blogdetail&sharerId=155931223&sharerefer=PC&sharesource=weixin_60668256&sharefrom=from_link

二.环境搭建

源码库地址:https://github.com/yhirose/cpp-httplib

镜像仓库: https://gitcode.net/mirrors/yhirose/cpp-httplib?utm_source=csdn_github_accelerator

"service" #include <iostream> #include <httplib.h> using std::cout; using std::endl; using std::cerr; using namespace httplib; int main() { cout << "--------服务启动--------" << endl; Server server; server.Post("/test-post", [](const Request& req, Response& res) { cout << "接收到post请求!" << endl; res.status = 200; }); server.Get("/test-get", [](const Request& req, Response& res) { cout << "接收到get请求!" << endl; res.status = 200; }); // 绑定 8123 端口,并且将端口号对外开放 server.listen("0.0.0.0", 8123); return 0; }
"client" #include <iostream> #include "httplib.h" using std::cout; using std::endl; using std::cerr; using namespace httplib; #define CONTACTS_HOST "192.168.205.128" #define CONTACTS_PORT 8123 int main() { Client cli(CONTACTS_HOST, CONTACTS_PORT); Result res1 = cli.Post("/test-post"); if (res1->status == 200) { cout << "调用post成功!" << endl; } Result res2 = cli.Get("/test-get"); if (res2->status == 200) { cout << "调用get成功!" << endl; } return 0; }

三.约定双端交互接口

四.约定双端交互req/resp

五.客户端代码实现

#include <iostream> #include "httplib.h" #include "ContactException.h" #include "add_contact.pb.h" using namespace std; using namespace httplib; #define CONTACTS_HOST "192.168.205.128" #define CONTACTS_PORT 8123 void buildAddContactRequest(add_contact::AddContactRequest& req) { cout << "---------------新增联系人-------------" << endl; cout << "请输入姓名:" << endl; string name; getline(cin,name); req.set_name(name); cout << "请输入联系人年龄" << endl; int age; cin >> age; req.set_age(age); cin.ignore(256,'\n'); for(int i = 0;;i++) { cout << "请输入" << i+1 << "个联系人电话: " << endl; string phone; getline(cin,phone); if(phone.empty()) { break; } add_contact::AddContactRequest::Phone* phone_number = req.add_phone(); phone_number->set_number(phone); cout << "请输入电话类型(1:移动电话,2:固定电话)" << endl; int type; cin >> type; cin.ignore(256,'\n'); switch(type) { case 1: phone_number->set_type(add_contact::AddContactRequest_Phone_PhoneType::AddContactRequest_Phone_PhoneType_MP); break; case 2: phone_number->set_type(add_contact::AddContactRequest_Phone_PhoneType::AddContactRequest_Phone_PhoneType_TEL); break; default: cout << "输入错误,请重新输入!" << endl; break; } } cout << "--------------新增联系人成功-------------" << endl; } void addContact() { //构造req add_contact::AddContactRequest req; buildAddContactRequest(req); //序列化req std::string req_str; if(!req.SerializeToString(&req_str)) { throw ContactException("AddContactRequest 序列化失败!"); } //发起post调用 Client cli(CONTACTS_HOST, CONTACTS_PORT); auto res = cli.Post("/contacts/add", req_str, "application/protobuf"); if(!res) { string err_desc; err_desc.append("/contacts/add 链接失败!错误信息: "); err_desc.append(httplib::to_string(res.error())); throw ContactException(err_desc); } //反序列化 add_contact::AddContactResponse resp; if(!resp.ParseFromString(res->body) && res->status != 200) { string err_desc; err_desc.append("/contacts/add 调用失败"); err_desc.append(httplib::to_string(res.error())); throw ContactException(err_desc); } else if(res->status != 200) { string err_desc; err_desc.append("/contacts/add 调用失败, 状态码: "); err_desc.append(std::to_string(res->status)); err_desc.append("错误原因: ").append(resp.error_desc()); throw ContactException(err_desc); } else if(!resp.success()) { string err_desc; err_desc.append("/contacts/add 结果异常"); err_desc.append("异常原因: ").append(resp.error_desc()); throw ContactException(err_desc); } //结果打印 cout << "新增联系人成功! uid: " << resp.uid() << endl; } void delContact() { } void findAllContacts() { } void findOneContact() { } void menu() { std::cout << "---------------------------------------------" << std::endl << "------------ 请选择对通讯录的操作 ------------" << std::endl << "------------ 1、新增联系人 -------------------" << std::endl << "------------ 2、删除联系人 -------------------" << std::endl << "------------ 3、查看联系人列表 ---------------" << std::endl << "------------ 4、查看联系人详细信息 -----------" << std::endl << "------------ 0、退出 -------------------------" << std::endl << "---------------------------------------------" << std::endl; } int main() { enum OPTION { QUIT = 0, ADD = 1, DEL = 2, FIND_ALL = 3, FIND_ONE = 4, }; while(true) { menu(); cout << "---> 请选择: "; int option = 0; cin >> option; cin.ignore(256,'\n'); try { switch(option) { case OPTION::QUIT: cout << "退出通讯录客户端!" << endl; break; case OPTION::ADD: cout << "新增联系人!" << endl; addContact(); break; case OPTION::DEL: cout << "删除联系人!" << endl; delContact(); break; case OPTION::FIND_ALL: cout << "查看联系人列表!" << endl; findAllContacts(); break; case OPTION::FIND_ONE: cout << "查看联系人详细信息!" << endl; findOneContact(); break; default: cout << "无效的选择!" << endl; break; } } catch(const ContactException& e) { cout << "操作通讯录时发生异常" << endl; cout << "异常信息: " << e.what() << endl; } } return 0; }

六.服务器的实现

#include <iostream> #include <httplib.h> #include "add_contact.pb.h" using namespace std; using namespace httplib; class ContactException { private: std::string message; public: ContactException(const std::string& str = "A problem") : message(str) {} ~ContactException() = default; const std::string& what() const { return message; } }; void printContact(add_contact::AddContactRequest& request) { cout << "联系人姓名: " << request.name() << endl; cout << "联系人年龄: " << request.age() << endl; for (int j = 0; j < request.phone_size(); j++) { const add_contact::AddContactRequest_Phone& phone = request.phone(j); cout << " 联系人电话" << j+1 << ": " << phone.number(); cout << " (" << phone.PhoneType_Name(phone.type()) << ")" << endl; } } static unsigned int random_char() { // 用于随机数引擎获得随机种子 std::random_device rd; // mt19937是c++11新特性,它是一种随机数算法,用法与rand()函数类似,但是mt19937具有速度快,周期长的特点 // 作用是生成伪随机数 std::mt19937 gen(rd()); // 随机生成一个整数i 范围[0, 255] std::uniform_int_distribution<> dis(0, 255); return dis(gen); } // 生成 UUID(通用唯一标识符) static std::string generate_hex(const unsigned int len) { std::stringstream ss; // 生成 len 个16进制随机数,将其拼接而成 for (auto i = 0; i < len; i++) { const auto rc = random_char(); std::stringstream hexstream; hexstream << std::hex << rc; auto hex = hexstream.str(); ss << (hex.length() < 2 ? '0' + hex : hex); } return ss.str(); } int main() { cout << "--------服务启动--------" << endl; Server server; server.Post("/contacts/add", [](const Request& req, Response& res) { cout << "接收到post请求!" << endl; //反序列化req.body add_contact::AddContactRequest request; add_contact::AddContactResponse response; try { if(!request.ParseFromString(req.body)) { throw ContactException("AddContactRequest反序列化失败!"); } //新增联系人,持久化存储通讯录 -> 打印新建的联系人信息 printContact(request); //构造 response res.body response.set_success(true); response.set_uid(generate_hex(16)); //序列化res.body string response_str; if(!response.SerializeToString(&response_str)) { throw ContactException("AddContactResponse序列化失败!"); } res.body = response_str; res.status = 200; res.set_header("Content-Type", "application/protobuf"); } catch(const ContactException& e) { res.status = 500; response.set_success(false); response.set_error_desc(e.what()); string response_str; if(response.SerializeToString(&response_str)) { res.body = response_str; res.set_header("Content-Type", "application/protobuf"); } cout << "/contacts/add 失败, 错误描述: " << e.what() << endl; } }); // 绑定 8123 端口,并且将端口号对外开放 server.listen("0.0.0.0", 8123); return 0; }

七.代码分析

1.服务端

2.客户端

其他的功能,有兴趣可以自己进行实现

八.总结

1.对比 PB 和 Json 的性能测试

"proto" syntax = "proto3"; package compare_serialization; import "google/protobuf/any.proto"; // 引⼊ any.proto ⽂件 // 地址 message Address{ string home_address = 1; // 家庭地址 string unit_address = 2; // 单位地址 } // 联系⼈ message PeopleInfo { string name = 1; // 姓名 int32 age = 2; // 年龄 message Phone { string number = 1; // 电话号码 enum PhoneType { MP = 0; // 移动电话 TEL = 1; // 固定电话 } PhoneType type = 2; // 类型 } repeated Phone phone = 3; // 电话 google.protobuf.Any data = 4; oneof other_contact { // 其他联系⽅式:多选⼀ string qq = 5; string weixin = 6; } map<string, string> remark = 7; // 备注 }
"compare.cc" #include <iostream> #include <sys/time.h> #include <jsoncpp/json/json.h> #include "contacts.pb.h" using namespace std; using namespace compare_serialization; using namespace google::protobuf; #define TEST_COUNT 100000 void createPeopleInfoFromPb(PeopleInfo *people_info_ptr); void createPeopleInfoFromJson(Json::Value& root); int main(int argc, char *argv[]) { struct timeval t_start,t_end; double time_used; int count; string pb_str, json_str; // ------------------------------Protobuf 序列化------------------------------------ { PeopleInfo pb_people; createPeopleInfoFromPb(&pb_people); count = TEST_COUNT; gettimeofday(&t_start, NULL); // 序列化count次 while ((count--) > 0) { pb_people.SerializeToString(&pb_str); } gettimeofday(&t_end, NULL); time_used=1000000*(t_end.tv_sec - t_start.tv_sec) + t_end.tv_usec - t_start.tv_usec; cout << TEST_COUNT << "次 [pb序列化]耗时:" << time_used/1000 << "ms." << " 序列化后的大小:" << pb_str.length() << endl; } // ------------------------------Protobuf 反序列化------------------------------------ { PeopleInfo pb_people; count = TEST_COUNT; gettimeofday(&t_start, NULL); // 反序列化count次 while ((count--) > 0) { pb_people.ParseFromString(pb_str); } gettimeofday(&t_end, NULL); time_used=1000000*(t_end.tv_sec - t_start.tv_sec) + t_end.tv_usec - t_start.tv_usec; cout << TEST_COUNT << "次 [pb反序列化]耗时:" << time_used / 1000 << "ms." << endl; } // ------------------------------JSON 序列化------------------------------------ { Json::Value json_people; createPeopleInfoFromJson(json_people); Json::StreamWriterBuilder builder; count = TEST_COUNT; gettimeofday(&t_start, NULL); // 序列化count次 while ((count--) > 0) { json_str = Json::writeString(builder, json_people); } gettimeofday(&t_end, NULL); // 打印序列化结果 // cout << "json: " << endl << json_str << endl; time_used=1000000*(t_end.tv_sec - t_start.tv_sec) + t_end.tv_usec - t_start.tv_usec; cout << TEST_COUNT << "次 [json序列化]耗时:" << time_used/1000 << "ms." << " 序列化后的大小:" << json_str.length() << endl; } // ------------------------------JSON 反序列化------------------------------------ { Json::CharReaderBuilder builder; unique_ptr<Json::CharReader> reader(builder.newCharReader()); Json::Value json_people; count = TEST_COUNT; gettimeofday(&t_start, NULL); // 反序列化count次 while ((count--) > 0) { reader->parse(json_str.c_str(), json_str.c_str() + json_str.length(), &json_people, nullptr); } gettimeofday(&t_end, NULL); time_used=1000000*(t_end.tv_sec - t_start.tv_sec) + t_end.tv_usec - t_start.tv_usec; cout << TEST_COUNT << "次 [json反序列化]耗时:" << time_used/1000 << "ms." << endl; } return 0; } /** * 构造pb对象 */ void createPeopleInfoFromPb(PeopleInfo *people_info_ptr) { people_info_ptr->set_name("张珊"); people_info_ptr->set_age(20); people_info_ptr->set_qq("95991122"); for(int i = 0; i < 5; i++) { PeopleInfo_Phone* phone = people_info_ptr->add_phone(); phone->set_number("110112119"); phone->set_type(PeopleInfo_Phone_PhoneType::PeopleInfo_Phone_PhoneType_MP); } Address address; address.set_home_address("陕西省西安市长安区"); address.set_unit_address("陕西省西安市雁塔区"); google::protobuf::Any * data = people_info_ptr->mutable_data(); />

2.总结

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/7/7 13:29:03

解决unable to connect to anthropic services问题,专注本地化Qwen图像编辑

解决 unable to connect to anthropic services 问题&#xff0c;专注本地化 Qwen 图像编辑 在电商运营、内容创作和数字营销的一线实践中&#xff0c;图像处理早已不再是“修图师Photoshop”的专属战场。如今&#xff0c;一个爆款商品图的诞生往往需要经历数十次微调&#xff…

作者头像 李华
网站建设 2026/7/7 7:28:18

基于SpringBoot的健身房课程预约管理系统的设计与实现_53h1m33j

目录具体实现截图项目介绍论文大纲核心代码部分展示项目运行指导结论源码获取详细视频演示 &#xff1a;文章底部获取博主联系方式&#xff01;同行可合作具体实现截图 本系统&#xff08;程序源码数据库调试部署讲解&#xff09;同时还支持java、ThinkPHP、Node.js、Spring B…

作者头像 李华
网站建设 2026/7/7 12:16:31

使用vLLM镜像加速transformer模型详解中的推理过程

使用vLLM镜像加速Transformer模型推理的工程实践与深度解析 在大模型落地日益迫切的今天&#xff0c;一个常见的现实是&#xff1a;我们训练出了强大的语言模型&#xff0c;却“跑不动”它。哪怕是一个7B参数量的LLaMA模型&#xff0c;在高并发请求下也可能因显存耗尽或响应延迟…

作者头像 李华
网站建设 2026/7/7 19:30:26

接口加密了该怎么测?

对明文编码生成信息摘要&#xff0c;以防止被篡改。比如MD5使用的是Hash算法&#xff0c;无论多长的输入&#xff0c;MD5都会输出长度为128bits的一个串。 摘要算法不要秘钥&#xff0c;客户端和服务端采用相同的摘要算法即可针对同一段明文获取一致的密文。 对称加密 对称加…

作者头像 李华
网站建设 2026/7/7 19:30:27

10个自考毕业答辩PPT工具,AI格式优化推荐

10个自考毕业答辩PPT工具&#xff0c;AI格式优化推荐 在时间与质量的夹缝中挣扎 对于自考学生来说&#xff0c;毕业答辩不仅是学业生涯的一个重要节点&#xff0c;更是对自身能力的一次全面检验。然而&#xff0c;在准备过程中&#xff0c;许多同学都会遇到一个共同的难题&…

作者头像 李华
网站建设 2026/7/7 18:29:48

10 个专科生论文写作工具,AI 写作神器推荐!

10 个专科生论文写作工具&#xff0c;AI 写作神器推荐&#xff01; 论文写作的“三座大山”&#xff1a;时间、重复率与效率 对于专科生来说&#xff0c;论文写作从来不是一件轻松的事。从选题到开题&#xff0c;从文献综述到正文撰写&#xff0c;每一个环节都充满了挑战。尤其…

作者头像 李华