文章目录

1. jsoncpp库接口使用测试2. bundle数据压缩库使用测试3. httplib库API使用测试httplib库Request类httplib库Response类httplib库Sever类httplib库Client类

4. httplib库快速搭建Http客户端服务器http服务器代码服务器运行截图华为云服务器开放端口

http客户端代码客户端运行截图

4. 库测试代码位置

1. jsoncpp库接口使用测试

jsoncpp库使用步骤;

序列化

将需要json化的数据保存在json::Value中使用Json::StreamWriter,Json::StreamWriterBuilder完成序列化

#include

#include

#include

#include

#include

int main(int argc, char const *argv[])

{

const char *name = "小米";

int age = 20;

float score[] = {77.5, 87.5, 90};

Json::Value value;

value["姓名"] = name;

value["年龄"] = age;

value["成绩"].append(score[0]);

value["成绩"].append(score[1]);

value["成绩"].append(score[2]);

Json::StreamWriterBuilder builder;

std::unique_ptr writer(builder.newStreamWriter());

std::stringstream ss;

writer->write(value, &ss);

std::cout << ss.str() << std::endl;

return 0;

}

反序列化

jsoncpp中的分序列化,是把json数据字符串放到 Json::Value对象中,取数据在 Json::Value上使用CharReaderBuilder CharReader类来实现反序列化

#include

#include

#include

#include

#include

using namespace std;

int main(int argc, char const *argv[])

{

string str = R"({"姓名":"小米","年龄":19,"成绩":[77.5,87.5,90]})"; // c++11语法R"(str)"

Json::Value value;

Json::CharReaderBuilder builder;

std::unique_ptr reader(builder.newCharReader());

string errs;

bool ok = reader->parse(str.c_str(), str.c_str() + str.size(), &value, &errs);

if (!ok)

{

std::cout << "parse error: " << errs << std::endl;

}

else

{

std::cout << "姓名: " << value["姓名"].asString() << std::endl;

std::cout << "年龄: " << value["年龄"].asInt() << std::endl;

std::cout << "成绩: " << value["成绩"][0].asFloat() << std::endl;

std::cout << "成绩: " << value["成绩"][1].asFloat() << std::endl;

std::cout << "成绩: " << value["成绩"][2].asFloat() << std::endl;

for(int i=0;i

std::cout<

}

}

return 0;

}

2. bundle数据压缩库使用测试

biundle库是一个嵌入代码式的压缩库,支持23种压缩算法和两种存档格式,使用时只需要加入bundle.h和bundle.cpp即可

bundle实现文件压缩与解压缩案例

压缩案例:

#include

#include

#include

#include "../bundle/bundle.h"

using namespace std;

int main(int argc, char const *argv[])

{

cout << "argv[1]是原始文件名称" << endl;

cout << "argv[2]是压缩后的文件名称" << endl;

if (argc < 3)

{

cout << "参数错误" << endl;

return 1;

}

string filename = argv[1];

string outname = argv[2];

ifstream file;

file.open(filename, std::ios::binary); // 二进制打开

file.seekg(0, std::ios::end); // 跳转到文件末尾,方便获取文件大小

size_t f_size = file.tellg();

file.seekg(0, std::ios::beg); // 跳转到文件开头

string body;

body.resize(f_size);

file.read(&body[0], f_size); // 文件内容读入body &body[0]为字符串首地址

file.close();

string packed = bundle::pack(bundle::LZIP, body); // 压缩后的数据,压缩格式为LZIP

ofstream outfile;

outfile.open(outname, std::ios::binary);

outfile.write(packed.c_str(), packed.size());

outfile.close();

cout << "压缩完成" << endl;

return 0;

}

因为库文件比较大,编译时间会比较长,警告忽视即可

解压案例

#include

#include

#include

#include "../bundle/bundle.h"

using namespace std;

int main(int argc, char const *argv[])

{

cout << "argv[1]是压缩包名称" << endl;

cout << "argv[2]是解压缩后的文件名称" << endl;

if (argc < 3)

{

cout << "参数错误" << endl;

return 1;

}

string infile = argv[1];

string outfile = argv[2];

ifstream inf;

inf.open(infile, std::ios::binary);

inf.seekg(0, std::ios::end);

int size = inf.tellg();

inf.seekg(0, std::ios::beg);

string body;

body.resize(size);

inf.read(&body[0], size);

inf.close();

string unpacked;

unpacked = bundle::unpack(body); // 解压

ofstream outf;

outf.open(outfile, std::ios::binary);

outf.write(unpacked.c_str(), unpacked.size());

outf.close();

cout << "解压缩成功" << endl;

return 0;

}

解压后的文件大小相同,计算文件的md5值看这两个文件是否相同 md5值完全相同

3. httplib库API使用测试

httplib库是一个C++11的单文件跨平台HTTP/HTTPS库,httplib库实际上是用于搭建一个简单http服务器的库,可以让我们免去搭建客户端服务器的时间。当然这个库也可以使用我的另一个项目HttpSever的部分代码,这里为了提升开发效率所以使用第三方库 HttpSever gitub代码 做过这个项目这个库的学习就会十分轻松了

httplib库Request类

httplib库Request类部分主要的源代码解析:

struct MultipartFormData {

std::string name; //字段名称

std::string content; //文件内容

std::string filename; //文件名称

std::string content_type; //正文类型

};

struct Request {

std::string method; //请求方法

std::string path; //请求uri

Headers headers; //请求头部字段

std::string body; //请求正文

// for server

std::string version; //协议版本

Params params; //保存查询字符串

MultipartFormDataMap files; //保存客户端上传的文件信息 key value型

Ranges ranges; //实现断点续传的请求文件区间

bool has_header(const std::string &key) const; //查询是否有某个头部字段

std::string get_header_value(const std::string &key, size_t id = 0) const; //获取头部字段的值

uint64_t get_header_value_u64(const std::string &key, size_t id = 0) const;

size_t get_header_value_count(const std::string &key) const;

void set_header(const std::string &key, const std::string &val); //设置头部字段的值

bool has_file(const std::string &key) const; //根据MultipartFormData中的name字段查找文件是否存在

MultipartFormData get_file_value(const std::string &key) const; //获取其中某一个文件信息

std::vector get_file_values(const std::string &key) const;

};

httplib库Request类作用:

客户端保存所有的Http请求相关信息,最终组织http请求发送给服务器服务器收到http请求之后进行解析,将解析数据保存在Request结构体上,待后续处理

httplib库Response类

httplib库Response类部分主要的源代码解析:

struct Response {

std::string version; //协议版本

int status = -1; //响应状态码

std::string reason;

Headers headers; //响应头部字段

std::string body; //响应正文

std::string location; // 重定向位置

void set_header(const std::string &key, const std::string &val); //设置头部字段

void set_content(const char *s, size_t n, const std::string &content_type); //设置正文

void set_content(const std::string &s, const std::string &content_type);

void set_content(std::string &&s, const std::string &content_type);

Response() = default;

Response(const Response &) = default;

Response &operator=(const Response &) = default;

Response(Response &&) = default;

Response &operator=(Response &&) = default;

~Response() {

if (content_provider_resource_releaser_) {

content_provider_resource_releaser_(content_provider_success_);

}

}

};

Response结构体功能:用户将响应数据放入结构中,httplib会将数据按照http响应格式组织成为http响应

httplib库Sever类

httplib库Sever类部分源码解析:

class Server {

public:

using Handler = std::function; //函数指针类型,定义了请求处理回调函数格式

/**

httplib搭建的服务器收到请求后,进行解析,得到Request结构体,其中包含了请求数据

根据请求数据处理请求,这个处理函数定义的格式就是Handler格式 void(const Request &, Response &)

Request参数,保存请求数据,让用户能根据请求数据进行业务处理

Response参数,需要用户在业务处理填充数据,最终发送给响应给客户端

*/

using Handlers =

std::vector>;//请求与处理函数映射表,那个函数用哪个函数处理

/**

regex:正则表达式,用来匹配http请求资源路径

Handler:请求处理函数指针

Handlers:是一张表,映射了客户端请求的资源路径和一个处理函数,

当服务器收到请求解析得到Request就会根据资源路径以及请求方法到这张表去查

如果有:调用这个函数进行处理

如果没有:响应404

*/

std::function new_task_queue; //线程池,用于处理请求

/**

httplib收到一个新建链接,则将新客户端链接抛入线程池中

线程池中的线程工作:

1. 接受数据,解析请求,得到Request结构体的数据

2. 在Handlers映射表中查找处理函数,如果有则调用,否则响应404

3. 当处理回调函数调用完毕,根据函数返回的Response结构体中的数据组织http响应发送给客户端

*/

//针对各种请求方法设定映射的处理函数,eg Get("/hello",hello/**(函数指针)*/) 会将Handlers映射表中添加新的映射

Server &Get(const std::string &pattern, Handler handler);

Server &Post(const std::string &pattern, Handler handler);

Server &Post(const std::string &pattern, HandlerWithContentReader handler);

Server &Put(const std::string &pattern, Handler handler);

Server &Put(const std::string &pattern, HandlerWithContentReader handler);

Server &Patch(const std::string &pattern, Handler handler);

Server &Patch(const std::string &pattern, HandlerWithContentReader handler);

Server &Delete(const std::string &pattern, Handler handler);

Server &Delete(const std::string &pattern, HandlerWithContentReader handler);

Server &Options(const std::string &pattern, Handler handler);

bool listen(const std::string &host, int port, int socket_flags = 0);//启动http服务器

};

Sever类功能:用来搭建Http服务器

httplib库Client类

httplib库Client类部分源码解析:

class Client {

public:

// HTTP only interface

explicit Client(const std::string &host, int port); //传入服务器ip地址和端口

Result Get(const std::string &path, const Headers &headers); //向服务器发送GET请求

Result Post(const std::string &path, const char *body, size_t content_length,

const std::string &content_type); //向服务器提供POST请求

Result Post(const std::string &path, const Headers &headers,

const MultipartFormDataItems &items); //items:是文件信息 post提交多区域数据,常见于多文件上传

};

4. httplib库快速搭建Http客户端服务器

http服务器代码

Server代码

#include "../httplib/httplib.h"

void Hello(const httplib::Request &req, httplib::Response &rsp)

{

rsp.set_content("Hello World!", "text/plain"); // 设置响应正文

rsp.status = 200;

}

void Numbers(const httplib::Request &req, httplib::Response &rsp)

{

auto num = req.matches[1]; // 0保存的是整体path 之后的下标中保存的是正则表达式捕捉的数据,就是uri /number/[i]的i

rsp.set_content(num, "text/plain"); // 设置响应正文

rsp.status = 200;

}

void Mutipart(const httplib::Request &req, httplib::Response &rsp)

{

auto ret = req.has_file("file");

if (ret == false)

{

std::cout << "不是文件上传\n"; // 通常 Mutipart用于上传数据

rsp.status = 404;

}

else

{

const auto &file = req.get_file_value("file");

rsp.body.clear();

rsp.body = file.filename;

rsp.body += "\n";

rsp.body += file.content;

rsp.set_header("Content-Type", "text/plain");

rsp.status = 200;

}

}

int main(int argc, char const *argv[])

{

httplib::Server svr; // 实例化Sever来搭建服务器

svr.Get("/hi", Hello); // 注册一个针对/hi的GET请求映射函数,处理方法为Hello的回调函数

svr.Get(R"(/numbers/(\d+))", Numbers); // 正则表达式/numbers/1 /numbers/2 .... 都会响应这个方法

svr.Post("/multipart", Mutipart);

svr.listen("0.0.0.0", 8081); // 匹配服务器所有网卡

return 0;

}

服务器运行截图

运行失败的,虚拟机记得关闭防火墙。云服务器记得开放端口

华为云服务器开放端口

http客户端代码

Client代码

#include "../httplib/httplib.h"

#define SEVER_IP "116.204.70.147"

#define SEVER_PORT 8081

int main(int argc, char const *argv[])

{

httplib::Client client(SEVER_IP, SEVER_PORT);

// 区域文件结构体

struct httplib::MultipartFormData item;

item.name = "file"; // 和服务器 /multipart post方法注册函数方法中处理的文件名一致

item.filename = "hello.txt";

item.content = "hello world"; // 这个文件的内容,为了省事,正常情况这个文件内容需要io读取

item.content_type = "text/plain";

httplib::MultipartFormDataItems items; // 一次性可以上传多个文件数据,本质是MultipartFormData数组

items.push_back(item);

httplib::Result response = client.Post("/multipart", items); // 与服务器注册的uri一致 ,向服务器发送POST请求

std::cout << "server response.status: " << response->status << std::endl;

std::cout << "server response.body: " << response->body << std::endl;

return 0;

}

客户端运行截图

4. 库测试代码位置

Gitee 库测试代码 Github 库测试代码

推荐阅读

评论可见,请评论后查看内容,谢谢!!!评论后请刷新页面。