一、项目介绍
自动将本地计算机上指定的文件夹中需要备份的文件上传备份到服务器中,并且能够随时通过浏览器进行查看并且下载,其中下载过程中支持断点续传功能,而服务器也会对上传文件进行热点管理,将非热点文件进行压缩存储,节省磁盘空间。
1.1 服务端
1.1.1 服务端程序负责功能
- 支持客户端文件上传功能
- 支持客户端问及那备份列表查看功能
- 支持客户端文件下载功能(断点续传)
- 支持热点文件管理功能(对长时间无访问的文件进行压缩)
1.1.2 服务端功能模块划分
- 数据管理模块(管理的是备份的文件信息,以便于随时获取)
- 网络通信模块(实现与客户端的网络通信)
- 业务处理模块(文件上传、文件列表、文件下载(断点续传))
- 热点管理模块(对长时间无访问的文件进行压缩存储)
1.2 客户端
1.2.1 客户端程序负责功能
- 能够自动检测客户主机指定文件夹中的文件,并判断是否需要备份
- 将需要备份的文件逐个上传到服务器
1.2.2 客户端功能模块划分
- 数据管理模块:负责客户端备份文件信息管理,通过这些数据可以确定一个文件是否需要备份
- 文件检测模块:便利获取指定文件夹中所有文件路径名称
- 网路通信模块:搭建网络通信客户端,实现将文件数据备份上传到服务器
二、第三方库
2.1 Jsoncpp库
**json 是一种数据交换格式,**采用完全独立于编程语言的文本格式来存储和表示数据。比如将一个一个的键值对组织成这种格式:
jsoncpp 库用于实现 json 格式的序列化和反序列化,完成将多个数据对象组织成为 json 格式字符串,以及将 json 格式字符串解析得到多个数据对象的功能。
2.1.1 Jsoncpp序列化实现
- 1.将所有的数据保存在Json::value对象中
- 2.使用Josn::StreamWriterBulider创建一个Josn::StreamWriter
- 2.使用Josn::StreamWriter,实现序列化
代码实现
#include<iostream>
3 #include<sstream>
4 #include<string>
5 #include<memory>
6 #include<jsoncpp/json/json.h>//添加头文件
7
8 int main()
9 {
10
11 const char *name="小明";
12 int age=18;
13 float score[]={
12,56.6,96.5};
14
15
16 Json::Value root;//创建实例化
17 root["姓名"]=name;
18 root["年龄"]=age;
19 root["成绩"].append(score[0]);
20 root["成绩"].append(score[1]);
21 root["成绩"].append(score[2]);
22
23
24 Json::StreamWriterBuilder swb;
25 std::unique_ptr<Json::StreamWriter> sw(swb.newStreamWriter());
26 std::stringstream ss;
27 sw->write(root,&ss);
28 std::cout<<ss.str()<<std::endl;
29 return 0;
30 }
实现结果
2.1.2 Jsoncpp反序列化实现
- 1.先定义一个Json:Value root
- 2.使用Josn::CharReaderBuilder创建一个Josn::CharReader
- 2.使用Josn::CharReader,实现序列化
代码实现
#include<iostream>
2 #include<string>
3 #include<memory>
4 #include<jsoncpp/json/json.h>
5 using namespace std;
6
7
8
9 int main()
10 {
11 string str= R"({"姓名":"小黑","年龄",19,"成绩":[58.5,76,19]})";
12
13
14 Json::Value root;
15 Json::CharReaderBuilder crb;
16 unique_ptr<Json::CharReader> cr (crb.newCharReader());
17 string err;
18 bool ret=cr->parse(str.c_str(),str.c_str()+str.size(),&root,&err);
19
20 if(ret==false)
21 {
22 cout<<"parse error"<<err<<endl;
23 return -1;
24 }
25
26 cout<<root["姓名"].asString()<<endl;
27 cout<<root["年龄"].asInt()<<endl;
28
29 int arr_size=root["成绩"].size();
30 for(int i=0;i<arr_size;++i)
31 {
32 cout<<root["成绩"][i]<<endl;
33 }
34 return 0;
35 }
2.2 Bundle库
数据压缩及解压缩库, 在本项目中服务端的热点管理模块, 若判断文件不是热点文件使用bundle库将其压缩用户下载时再将其解压缩.(因为bundle.cpp过于庞大, 编译较慢 在项目中将其生成为一个静态库使用)
2.2.1Bundle库实现压缩文件
压缩代码实现
#include<iostream>
2 #include<string>
3 #include<fstream>
4 #include<bundle.h>
5
6 using namespace std;
7
8 int main(int argc,char* argv[])
9 {
10 cout<<"argv[1]是原始文件路径名称\n";
11 cout<<"argv[2]是压缩包名称\n";
12 if(argc<3) return -1;
13
14 string ifilename=argv[1];
15 string ofilename=argv[2];
16
17 ifstream ifs;
18 ifs.open(ifilename,ios::binary);//打开原始文件
E> 19 ifs.seekg(0,std::ios::end());//跳转至读写位置末尾
20 size_t fsize=ifs.tellg();//获取末尾偏移量——获得文件长度
E> 21 ifs.seekg(0,std::ios::beg());//跳转至文件开头
22 string body;//创建临时文件
23 body.resize(fsize);//调整临时文件大小
24 ifs.read(&body[0],fsize);//将原始文件中所有数据读取到body中
25
26
27 string packed=bundle::pack(bundle::LZIP,body);//将body中的数据以lzip格式压缩文件
28
29 ofstream ofs;
30 ofs.open(ofilename,ios::binary);//以二进制格式打开压缩文件
31 ofs.write(&packed[0],packed.size());//将压缩后的数据写入压缩包中
32
33
34 ifs.close();
35 ofs.close();
36
37 }
2.2.1Bundle库实现解压缩文件
代码实现
#include<iostream>
#include<string>
#include<fstream>
#include<bundle.h>
using namespace std;
int main(int argc,char* argv[])
{
cout<<"argv[1]是压缩包文件名称\n";
cout<<"argv[2]是解压缩包名称\n";
if(argc<3) return -1;
string ifilename=argv[1];
string ofilename=argv[2];
ifstream ifs;
ifs.open(ifilename,ios::binary);//打开原始文件
ifs.seekg(0,std::ios::end);//跳转至读写位置末尾
size_t fsize=ifs.tellg();//获取末尾偏移量——获得文件长度
ifs.seekg(0,std::ios::beg);//跳转至文件开头
string body;//创建临时文件
body.resize(fsize);//调整临时文件大小
ifs.read(&body[0],fsize);//将原始文件中所有数据读取到body中
ifs.close();
string unpacked=bundle::unpack(body);//解压
ofstream ofs;
ofs.open(ofilename,ios::binary);//以二进制格式打开压缩文件
ofs.write(&packed[0],packed.size());//将压缩后的数据写入解压缩包中
ofs.close();
return 0;
}
2.3 Httplib库
在本项目中, 服务端使用httplib库实现业务处理模块, 处理客户端发来的上传, 查看, 下载三个请求, 客户端使用其实现文件的上传.(客户端的查看, 下载请求通过浏览器直接输入实现). 在传输层是基于tcp实现传输的。
HTTPLIB库实际上是用于搭建一个简单的http服务器或者客户端的库,这种第三方网络库,可以让我们免去搭建服务器或客户端的时间,把更多的精力投入到具体的业务处理中,提高开发效率。
2.3.1 httplib库中的request类
Request结构体的作用
- 客户端保存所有http请求相关信息,最终组织http请求发送给服务器
- 服务器收到http请求后及进行解析,将解析的数据保存在request结构体中,等待后续处理。
2.3.2 httplib库中的response类
response结构体功能:
- 用户将响应数据放到结构体中,httplib会将其中的数据按照http响应格式组织成为http响应,发送给客户端。
2.3.3 httplib库中的server类
server类功能:用于搭建http服务器。
Handler
Handlers
new_task_queue
2.3.4 httplib库中的client类
2.3.5 基于httplib库搭建简单服务器
代码实现
#include<iostream>
#include"cpp-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,往后的下标保存的是捕捉的数据
rsp.set_content(num,"text/plain");
rsp.status=200;
}
void Multipart(const httplib::Request &req,httplib::Response &rsp)
{
auto ret=req.has_file("file");
if(ret