建网站学什么,温州网站托管,wordpress多媒体大小,微信公众官网登录入口一、介绍
该项目的主要目的是用于熟悉protobuf的使用#xff0c;体验数据在网络中序列化反序列化的形式#xff0c;并非一个完整的项目。
该通讯录只实现了增加联系人的功能。服务器端接收到请求后会将联系人的信息打印。
二、环境搭建
使用Httplib库#xff0c;可以快速…一、介绍
该项目的主要目的是用于熟悉protobuf的使用体验数据在网络中序列化反序列化的形式并非一个完整的项目。
该通讯录只实现了增加联系人的功能。服务器端接收到请求后会将联系人的信息打印。
二、环境搭建
使用Httplib库可以快速完成客户端与服务器的搭建。
Httplib库cpp-httplib是个开源的库是⼀个c封装的http库使⽤这个库可以在linux、windows平台下完成http客户端、http服务端的搭建。使⽤起来⾮常⽅便只需要包含头⽂件httplib.h即可。编译程序时需要带上-lpthread选项。 源码库地址https://github.com/yhirose/cpp-httplib
点击如图httplib.h文件然后再点击下载该文件。 下载好后在linux下使用rz指令将该头文件上传到linux的项目路径下。
注意
如果使⽤centOS环境yum源带的g最新版本是4.8.5发布于2015年年代久远。编译该项⽬会出现异常。将gcc/g升级为更⾼版本可解决问题。 可以通过指令gcc -v查看gcc的版本如果以8.开头的版本则需要更新一下。
更新方法可以参考这篇文章CentOS 7上升级/安装gcc - 掘金
syntax proto3;
package add_contact;// 新增联系人 req
message AddContactRequest {string name 1; // 姓名 int32 age 2; // 年龄 message Phone { string number 1; // 电话号码enum PhoneType { MP 0; // 移动电话TEL 1; // 固定电话} PhoneType type 2; // 类型 }repeated Phone phone 3; // 电话
} message AddContactResponse{bool success 1; // 服务调用是否成功string error_desc 2; //错误原因 string uid 3;
}
五、自定义异常类
#include iostream
#include string// ⾃定义异常类
class ContactException
{
private:std::string message;public:ContactException(std::string str A problem) : message{str} {}std::string what() const { return message; }
};
六、客户端
客户端使用前面下载的httplib.h中的Client类来实现客户端的构造
Client cli(CONTACTS_HOST, CONTACTS_PORT);
参数包含CONTACTS_HOST服务器的ip地址CONTACTS_PORT服务器的端口号来与服务器建立链接。
void addContact()
{Client cli(CONTACTS_HOST, CONTACTS_PORT); // 构造reqadd_contact::AddContactRequest req;buidAddContactRequest(req);// 序列化string req_str;if(!req.SerializeToString(req_str)){throw ContactException(AddContactRequest is fail);}// 发起post调用auto res cli.Post(/contacts/add, req_str, application/protobuf);if(!res) // 失败{string err_desc;err_desc.append(/contacts/add 链接失败 错误信息: ).append(httplib::to_string(res.error()));throw ContactException(err_desc);}//反序列化add_contact::AddContactResponse resp;bool parse resp.ParseFromString(res-body);if(res-status ! 200 !parse){string err_desc;err_desc.append(/contact/add 调用失败).append(std::to_string(res-status)).append(().append(res-reason).append());throw ContactException(err_desc);}else if(res-status ! 200){string err_desc;err_desc.append(/contact/add 调用失败).append(std::to_string(res-status)).append(().append(res-reason).append() 错误原因).append(resp.error_desc());throw ContactException(err_desc);}else if(!resp.success()){string err_desc;err_desc.append(/contact/add 结果异常).append(异常原因).append(resp.error_desc());throw ContactException(err_desc);}// 结果打印cout 新增联系人成功联系人ID:resp.uid()endl;
}
完整代码
#include iostream
#include httplib.h
#include ContactsException.h
#include add_contact.pb.husing namespace httplib;
using namespace std;#define CONTACTS_HOST 120.55.73.49
#define CONTACTS_PORT 8080void addContact();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,DEL,FIND_ONE,FIND_ALL};while(true){menu();cout 请选择:endl;int choose;cin choose;cin.ignore(256, \n);try{switch(choose){case OPTION::QUIT:cout---程序退出---endl;return 0;case OPTION::ADD:addContact();break;case OPTION::DEL:break;case OPTION::FIND_ONE:break;case OPTION::FIND_ALL:break;default:cout选择错误请重新选择:endl;break;}}catch(const ContactException e){cout ---操作通讯录时发生异常endl ---异常信息 e.what() endl;}}return 0;
}void buidAddContactRequest(add_contact::AddContactRequest* req)
{cout --------新增联系人--------endl;cout 请输入姓名: ;string name;getline(cin, name);req-set_name(name);cout 请输入年龄: ;int age;cin age;req-set_age(age);cin.ignore(256, \n); // 清除输入缓冲区里面内容// 输入电话号码for(int i0; ; i){cout 请输入联系人电话 i1 (只输入回车表示结束)endl;string number;getline(cin, number);if(number.empty()){break;}add_contact::AddContactRequest_Phone* phone req-add_phone();phone-set_number(number);cout 请输入电话类型(1.移动电话 2.座机): ;int type;cintype;cin.ignore(256, \n);switch(type){case 1:phone-set_type(add_contact::AddContactRequest_Phone_PhoneType::AddContactRequest_Phone_PhoneType_MP);break;case 2:phone-set_type(add_contact::AddContactRequest_Phone_PhoneType::AddContactRequest_Phone_PhoneType_TEL);break;default:cout输入有误endl;break;}}
}void addContact()
{Client cli(CONTACTS_HOST, CONTACTS_PORT); // 构造reqadd_contact::AddContactRequest req;buidAddContactRequest(req);// 序列化string req_str;if(!req.SerializeToString(req_str)){throw ContactException(AddContactRequest is fail);}// 发起post调用auto res cli.Post(/contacts/add, req_str, application/protobuf);if(!res){string err_desc;err_desc.append(/contacts/add 链接失败 错误信息: ).append(httplib::to_string(res.error()));throw ContactException(err_desc);}//反序列化add_contact::AddContactResponse resp;bool parse resp.ParseFromString(res-body);if(res-status ! 200 !parse){string err_desc;err_desc.append(/contact/add 调用失败).append(std::to_string(res-status)).append(().append(res-reason).append());throw ContactException(err_desc);}else if(res-status ! 200){string err_desc;err_desc.append(/contact/add 调用失败).append(std::to_string(res-status)).append(().append(res-reason).append() 错误原因).append(resp.error_desc());throw ContactException(err_desc);}else if(!resp.success()){string err_desc;err_desc.append(/contact/add 结果异常).append(异常原因).append(resp.error_desc());throw ContactException(err_desc);}// 结果打印cout 新增联系人成功联系人ID:resp.uid()endl;
}七、服务器
void printContact(add_contact::AddContactRequest req)打印req所包含的联系人信息
static unsigned int random_char()生成一个0~255范围内的随机数
static std::string generate_hex(const unsigned int len)⽣成 UUID 通⽤唯⼀标识符
std::hex将流中的整数以十六进制形式输出。
Server server使用httplib.h中的Server类构造服务器。
server.Post:参数中使用了lambda表达式接收客户端的请求和响应。
#include iostream
#include httplib.h
#include add_contact.pb.husing namespace httplib;
using namespace std;// ⾃定义异常类
class ContactException
{
private:std::string message;public:ContactException(std::string str A problem) : message{str} {}std::string what() const { return message; }
};void printContact(add_contact::AddContactRequest req)
{cout 姓名: req.name() endl;cout 年龄: req.age() endl;for (int j 0; j req.phone_size(); j){const add_contact::AddContactRequest_Phone phone req.phone(j);cout 联系电话 phone.number() ( phone.PhoneType_Name(phone.type()) ) endl;// phone.type() 获取的是int值phone.PhoneType_Name(phone.type())是根据int值转为对应的常量名string。}
}static unsigned int random_char() {// ⽤于随机数引擎获得随机种⼦std::random_device rd;// mt19937是c11新特性它是⼀种随机数算法⽤法与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; // 生成的随机数转为16进制流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;// 反序列化add_contact::AddContactRequest request;add_contact::AddContactResponse response;try{if (!request.ParseFromString(req.body)){throw ContactException(AddContactRequest 反序列化失败);}// 新增联系人持久化逻辑--》打印新增联系人信息printContact(request);// 构造返回结果 response.bodyresponse.set_success(true);response.set_uid(generate_hex(10));// res.body 序列化responsestring response_str;if (!response.SerializeToString(response_str)){throw ContactException(ADDcontactRequest序列化失败);}res.status 200;res.body response_str;res.set_header(Contact-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 /contact/add 发生异常 信息 e.what() endl;} });// 绑定端口且对外开放server.listen(0.0.0.0, 8080);return 0;
}
八、运行结果