云备份项目认识、环境搭建以及所使用的库的介绍

一、云备份认识

将本地计算机一个受监管的文件夹的文件上传到服务器中,有服务器组织,客户端可以通过网页将文件查看并且下载下来,下载过程支持断点续传功能,并且服务器会对上传的文件进行热点管理,长时间没人访问的文件夹会被压缩,以节省磁盘空间。

二、如何实现

这个项目需要我们在服务器与客户端两端都搭载程序,客户端负责上传、服务端负责管理。

三、服务端程序负责功能

  • 针对客户端文件进行上传储存
  • 能够对文件进行热点文件管理、对非热点文件压缩、节省磁盘空间
  • 支持客户端访问查看文件列表
  • 支持客户端浏览器下载文件、并实现断点续传

四、客户端程序负责功能呢

  • 能够自动检测指定文件夹中的文件,并判断是否需要上传文件
  • 将需要上传的文件组个上传

五、环境搭建

将服务器上的gcc替换成7.3版本,这里需要注意的是这个版本并不会有很强的向下兼容性——所以不能想着用更高的版本代替它,我们这里用的是7.3。这里默认的是centos的linux操作系统

sudo yum install centos-release-scl-rh centos-release-scl
sudo yum install devtoolset-7-gcc devtoolset-7-gcc-c++
source /opt/rh/devtoolset-7/enable 
echo "source /opt/rh/devtoolset-7/enable" >> ~/.bashrc
g++ -v //通过这个查看现在的版本是否正确

六、库的安装

我们需要安装jsoncpp库来实现序列化以及反序列化、bundle库来实现数据的压缩以及解压缩、httplib库搭建网络服务器接收请求

jsoncpp库

安装jsoncpp库:

sudo yum install epel-release
sudo yum install jsoncpp-devells /usr/include/jsoncpp/json/  
assertions.h config.h   forwards.h reader.h version.h
autolink.h   features.h json.h     value.h   writer.h
#注意,centos版本不同有可能安装的jsoncpp版本不同,安装的头文件位置也就可能不同了。

通过第三行的指令我们能看到安装下来的东西。

json的作用是将

char name = "小明";
int age = 18;
float score[3] = {88.5, 99, 58};

这样的数据,转换成:

[{"姓名" : "小明","年龄" : 18,"成绩" : [88.5, 99, 58]},{"姓名" : "小黑","年龄" : 18,"成绩" : [88.5, 99, 58]}
]

这样的数据,这个过程就是序列化。

序列化实现原理:

要实现序列化,我们首先需要一个容器来装载需要序列化的数据——也就是value,也被称为万能变量。

//Json数据对象类
class Json::Value{Value &operator=(const Value &other); //Value重载了[]和=,因此所有的赋值和获取数据都可以通过Value& operator[](const std::string& key);//简单的方式完成 val["姓名"] = "小明";Value& operator[](const char* key);Value removeMember(const char* key);//移除元素const Value& operator[](ArrayIndex index) const; //val["成绩"][0]Value& append(const Value& value);//添加数组元素val["成绩"].append(88); ArrayIndex size() const;//获取数组元素个数 val["成绩"].size();std::string asString() const;//转string string name = val["name"].asString();const char* asCString() const;//转char*   char *name = val["name"].asCString();Int asInt() const;//转int int age = val["age"].asInt();float asFloat() const;//转floatbool asBool() const;//转 bool
};
//json序列化类,低版本用这个更简单
class JSON_API Writer {virtual std::string write(const Value& root) = 0;
}
class JSON_API FastWriter : public Writer {virtual std::string write(const Value& root);
}
class JSON_API StyledWriter : public Writer {virtual std::string write(const Value& root);
}
//json序列化类,高版本推荐,如果用低版本的接口可能会有警告
class JSON_API StreamWriter {virtual int write(Value const& root, std::ostream* sout) = 0;
}
class JSON_API StreamWriterBuilder : public StreamWriter::Factory {virtual StreamWriter* newStreamWriter() const;
}
//json反序列化类,低版本用起来更简单
class JSON_API Reader {bool parse(const std::string& document, Value& root, bool collectComments = true);
}
//json反序列化类,高版本更推荐
class JSON_API CharReader {virtual bool parse(char const* beginDoc, char const* endDoc, Value* root, std::string* errs) = 0;
}
class JSON_API CharReaderBuilder : public CharReader::Factory {virtual CharReader* newCharReader() const;
}

 实现序列化:

int main()
{const char *name = "小明";int age = 18;float score[] = {88.5, 98, 58};Json::Value val;val["姓名"] = name;val["年龄"] = age;val["成绩"].append(score[0]);val["成绩"].append(score[1]);val["成绩"].append(score[2]);Json::StreamWriterBuilder swb;std::unique_ptr<Json::StreamWriter> sw(swb.newStreamWriter());std::ostringstream os;sw->write(val, &os);std::string str = os.str();std::cout << str <<std::endl;return 0;
}
g++ json_example1.cpp -o json_example1 -ljsoncpp

经过序列化后的val值就是{"姓名":"小明", "年龄":18, "成绩":[76.5, 55, 88]}这样的。

实现反序列化:

int main()
{std::string str = R"({"姓名":"小明", "年龄":18, "成绩":[76.5, 55, 88]})";Json::Value root;Json::CharReaderBuilder crb;std::unique_ptr<Json::CharReader> cr(crb.newCharReader());std::string err;cr->parse(str.c_str(), str.c_str() + str.size(), &root, &err);std::cout << root["姓名"].asString() << std::endl;std::cout << root["年龄"].asInt() << std::endl;int sz = root["成绩"].size();for (int i = 0; i < sz; i++) {std::cout << root["成绩"][i].asFloat() << std::endl;}for (auto it = root["成绩"].begin(); it != root["成绩"].end(); it++){std::cout << it->asFloat() << std::endl;}return 0;
}

反序列化就是将被限定格式的字符串变成一个个我们想要的数据。将root里面的数据像数组一样一个个取出来,归功于Value对于[]和=的重载。

序列化与反序列化的原理就是:自己规定一个字符串格式,然后将数据以这种格式储存起来。然后在想要取出数据的时候再凭借我们对这个格式的了解将其中的数据一个个取出来即可

json库主要运用与服务器端,客户端需要储存的数据没有这么复杂,我们可以自己写一个序列化的操作练一下手。

bundle库

bundle库的安装:

bundle是一个嵌入式库,使用的时候只需要将bundle.cpp和bundle.hpp放入项目文件即可,可以从我的gitee上进行下载gitee项目地址

bundle的认识:

namespace bundle
{// low level API (raw pointers)bool is_packed( *ptr, len );bool is_unpacked( *ptr, len );unsigned type_of( *ptr, len );size_t len( *ptr, len );size_t zlen( *ptr, len );const void *zptr( *ptr, len );bool pack( unsigned Q, *in, len, *out, &zlen );bool unpack( unsigned Q, *in, len, *out, &zlen );// medium level API, templates (in-place)bool is_packed( T );bool is_unpacked( T );unsigned type_of( T );size_t len( T );size_t zlen( T );const void *zptr( T );bool unpack( T &, T );bool pack( unsigned Q, T &, T );// high level API, templates (copy)T pack( unsigned Q, T );T unpack( T );
}

 bundle的压缩:

#include <iostream>
#include <string>
#include <fstream>
#include "bundle.h"
int main(int argc, char *argv[])
{std::cout <<"argv[1] 是原始文件路径名称\n";std::cout <<"argv[2] 是压缩包名称\n";if (argc < 3) return -1;std::string ifilename = argv[1];std::string ofilename = argv[2];std::ifstream ifs;ifs.open(ifilename, std::ios::binary);//打开原始文件ifs.seekg(0, std::ios::end);//跳转读写位置到末尾size_t fsize = ifs.tellg();//获取末尾偏移量--文件长度ifs.seekg(0, std::ios::beg);//跳转到文件起始std::string body;body.resize(fsize);//调整body大小为文件大小ifs.read(&body[0], fsize);//读取文件所有数据到body找给你std::string packed = bundle::pack(bundle::LZIP, body);//以lzip格式压缩文件数据std::ofstream ofs;ofs.open(ofilename, std::ios::binary);//打开压缩包文件ofs.write(&packed[0], packed.size());//将压缩后的数据写入压缩包文件ifs.close();ofs.close();return 0;
}

bundle的解压缩:

#include <iostream>
#include <fstream>
int main(int argc, char *argv[])
{if (argc < 3) {printf("argv[1]是压缩包名称\n");printf("argv[2]是解压后的文件名称\n");return -1; }   std::string ifilename = argv[1];//压缩包名std::string ofilename = argv[2];//解压缩后文件名std::ifstream ifs;ifs.open(ifilename, std::ios::binary);ifs.seekg(0, std::ios::end);size_t fsize = ifs.tellg();ifs.seekg(0, std::ios::beg);std::string body;body.resize(fsize);ifs.read(&body[0], fsize);ifs.close();std::string unpacked = bundle::unpack(body);//对压缩包数据解压缩std::ofstream ofs;ofs.open(ofilename, std::ios::binary);ofs.write(&unpacked[0], unpacked.size());ofs.close();return 0;
}

需要注意的是:bundle库的压缩会使用到线程,所以在编译时需要加上调用的线程库:

 g++ compress.cpp bundle.cpp -o compress -lpthreadg++ uncompress.cpp bundle.cpp -o uncompress -lpthread
./compress ./bundle.cpp ./bundle.cpp.lz
./uncompress ./bundle.cpp.lz ./bundle2.cpp

httplib库

httplib 库,一个 C++11 单文件头的跨平台 HTTP/HTTPS 库。安装起来非常容易。只需包含 httplib.h 在你的代码 中即可。
httplib 库实际上是用于搭建一个简单的 http 服务器或者客户端的库,这种第三方网络库,可以让我们免去搭建服务器或客户端的时间,把更多的精力投入到具体的业务处理中,提高开发效率。
namespace httplib{struct MultipartFormData {std::string name;std::string content;std::string filename;std::string content_type;};using MultipartFormDataItems = std::vector<MultipartFormData>;struct Request {std::string method;std::string path;Headers headers;std::string body;// for serverstd::string version;Params params;MultipartFormDataMap files;Ranges ranges;bool has_header(const char *key) const;std::string get_header_value(const char *key, size_t id = 0) const;void set_header(const char *key, const char *val);bool has_file(const char *key) const;MultipartFormData get_file_value(const char *key) const;};struct Response {std::string version;int status = -1;std::string reason;Headers headers;std::string body;std::string location; // Redirect locationvoid set_header(const char *key, const char *val);void set_content(const std::string &s, const char *content_type);};class Server {using Handler = std::function<void(const Request &, Response &)>;using Handlers = std::vector<std::pair<std::regex, Handler>>;std::function<TaskQueue *(void)> new_task_queue;Server &Get(const std::string &pattern, Handler handler);Server &Post(const std::string &pattern, Handler handler);Server &Put(const std::string &pattern, Handler handler);Server &Patch(const std::string &pattern, Handler handler);  Server &Delete(const std::string &pattern, Handler handler);Server &Options(const std::string &pattern, Handler handler);bool listen(const char *host, int port, int socket_flags = 0);};class Client {Client(const std::string &host, int port);Result Get(const char *path, const Headers &headers);Result Post(const char *path, const char *body, size_t content_length,const char *content_type);Result Post(const char *path, const MultipartFormDataItems &items);}
}

前端测试页面:

/* 前端测试页面 test.html 直接使用浏览器打开即可看到网页 */
<html><body><form action="http://服务器IP:端口/upload" method="post" enctype="multipart/form-data"><input type="file" name="file"><input type="submit" value="上传"></form></body>
</html>

简易服务器的搭建:

#include "httplib.h"
int main(void)
{using namespace httplib;Server svr;svr.Get("/hi", [](const Request& req, Response& res) {res.set_content("Hello World!", "text/plain");});svr.Get(R"(/numbers/(\d+))", [&](const Request& req, Response& res) {auto numbers = req.matches[1];res.set_content(numbers, "text/plain");});svr.Post("/upload", [&](const auto& req, auto& res) {auto size = req.files.size();auto ret = req.has_file("file1");const auto& file = req.get_file_value("file1");std::cout << file.filename << std::endl;std::cout <<  file.content_type << std::endl;std::cout <<  file.content << std::endl;});svr.listen("0.0.0.0", 9090);return 0; 
}
//g++ -std=c++14 http_server.cpp -o http_server -lpthread

简易客户端:

#include "httplib.h"
#define SERVER_IP "你的服务器IP地址"
// HTTP
int main()
{httplib::Client cli(SERVER_IP);auto res = cli.Get("/hi");std::cout << res->status << std::endl;std::cout << res->body << std::endl;auto res = cli.Get("/numbers/678");std::cout << res->status << std::endl;std::cout << res->body << std::endl;httplib::MultipartFormDataItems items = {{ "file1", "this is file content", "hello.txt", "text/plain" },};auto res = cli.Post("/upload", items);std::cout << res->status << std::endl;std::cout << res->body << std::endl;return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/784471.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

内网穿透时报错【Bad Request This combination of host and port requires TLS.】的原因

目录 前言&#xff1a;介绍一下内网穿透 1.内网直接https访问&#xff08;可以正常访问&#xff09; 程序配置的证书 2.内网穿透后,通过外网访问 3.原因 4.内网非https的Web应用&#xff0c;使用https后&#xff0c;也变成了https访问 5.题外话 感觉自己的web应用配置了…

使用 Seq2Seq 模型进行文本摘要

目录 引言 1 导入数据集 2 清洗数据集 3 确定允许的最大序列长度 4 选择合理的文本和摘要 5 对文本进行标记 6 删除空文本和摘要 7 构建模型 7.1 编码器 7.2 解码器 8 训练模型 9 测试模型 10 注意 11 整体代码 引言 文本摘要是指在捕捉其本质的同时缩短长文本的…

分布式之分布式事务详解

分布式事务与实战运用 什么是分布式事务&#xff1f; 业务场景&#xff1a;用户A转账100元给用户B&#xff0c;这个业务比较简单&#xff0c;具体的步骤&#xff1a; 1、用户A的账户先扣除100元 2、再把用户B的账户加100元 如果在同一个数据库中进行&#xff0c;事务可以保证…

209基于matlab的无人机路径规划

基于matlab的无人机路径规划&#xff0c;包括2D路径和3D路径&#xff0c;三种优化算法&#xff0c;分别是蝙蝠算法&#xff08;BA&#xff09;、蝙蝠算法融合差分进化算法(DEBA)、结合人工势场方法的改进混沌蝙蝠算法(CPFIBA)。输出距离迭代曲线和规划的路径。程序已调通&#…

云计算探索-如何在服务器上配置RAID(附模拟器)

一&#xff0c;引言 RAID&#xff08;Redundant Array of Independent Disks&#xff09;是一种将多个物理硬盘组合成一个逻辑单元的技术&#xff0c;旨在提升数据存取速度、增大存储容量以及提高数据可靠性。在服务器环境中配置RAID尤其重要&#xff0c;它不仅能够应对高并发访…

【跟小嘉学 Linux 系统架构与开发】二、Linux发型版介绍与基础常用命令介绍

系列文章目录 【跟小嘉学 Linux 系统架构与开发】一、学习环境的准备与Linux系统介绍 【跟小嘉学 Linux 系统架构与开发】二、Linux发型版介绍与基础常用命令介绍 文章目录 系列文章目录[TOC](文章目录) 前言一、 Linux 发行版(Linux distribution)介绍二、Centos 虚拟机初始化…

Yarn的安装和使用(2):使用及问题解决

Yarn是JavaScript的依赖管理工具&#xff0c;它与npm类似&#xff0c;但提供了一些额外的性能优化和一致性保证。 Yarn的使用&#xff1a; 初始化项目&#xff1a; yarn init 此命令会引导您创建一个新的package.json文件&#xff0c;用于记录项目的元信息和依赖。 添加依赖&…

【Linux在程序运行时打印调用栈信息(函数名,文件行号等)】

在程序运行时打印相关调用栈信息&#xff08;函数名&#xff0c;文件行号等&#xff09;,便于梳理调用逻辑等 //stack.c #include <stdio.h> #include <execinfo.h> #include <stdlib.h> #include <string.h> #include <stdbool.h>#define MAX_…

如何通过Elasticsearch实现搜索的关键词达到高亮的效果

高亮 首先介绍一下什么是搜索的关键词达到高亮的效果&#xff0c;如图所示 当在百度里面搜索elasticsearch的时候&#xff0c;可以看到出现的搜索结果里面elasticsearch这个关键词明显与其他的条文不一样&#xff0c;用红颜色凸显了“高亮效果”。当我们想要在自己的项目里面…

手机有线投屏到直播姬pc端教程

1 打开哔哩哔哩直播姬客户端并登录(按下图进行操作) 2 手机用usb数据线连接电脑(若跳出安装驱动的弹窗点击确定或允许),usb的连接方式为仅充电(手机差异要求为仅充电),不同品牌手机要求可能不一样,根据实际的来 3 在投屏过程中不要更改usb的连接方式(不然电脑会死机需要重启) …

MultiPath HTTP:北大与华为合作部署FLEETY

当前的终端基本都能支持蜂窝网络和wifi网络&#xff0c;然而&#xff0c;不同的网络通路都不可避免的会出现信号不好或者其他因素引起的通路性能(吞吐量、时延等)下降。为了能够提升终端业务体验&#xff0c;很多不同的MultiPath方案被提出&#xff0c;其中&#xff0c;包括应用…

使用Detours进行HOOK

文章目录 Detours介绍Detours配置Detours进行Sleep Hook Detours介绍 Detours是微软研究院开发的一款软件工具&#xff0c;用于Windows平台上的应用程序重定向和修改。 它可以在运行时修改应用程序的执行路径&#xff0c;允许开发人员注入自定义代码来改变应用程序的 行为&…

vulhub中Apache Solr 远程命令执行漏洞复现(CVE-2017-12629)

Apache Solr 是一个开源的搜索服务器。Solr 使用 Java 语言开发&#xff0c;主要基于 HTTP 和 Apache Lucene 实现。原理大致是文档通过Http利用XML加到一个搜索集合中。查询该集合也是通过 http收到一个XML/JSON响应来实现。此次7.1.0之前版本总共爆出两个漏洞&#xff1a;[XM…

[Flutter]打包IPA

1.直接使用Xcode运行iOS工程 不用flutter构建&#xff0c;在Xcode中是可以独立进行构建运行和打包发布的。 1).运行项目 先将flutter的build清理 $ flutter clean $ flutter pub get 然后立即用XCode打开iOS工程运行 运行会报错&#xff1a; error: The sandbox is not …

C刊级 | Matlab实现DBO-BiTCN-BiGRU-Attention蜣螂算法优化双向时间卷积双向门控循环单元融合注意力机制多变量回归预测

C刊级 | Matlab实现DBO-BiTCN-BiGRU-Attention蜣螂算法优化双向时间卷积双向门控循环单元融合注意力机制多变量回归预测 目录 C刊级 | Matlab实现DBO-BiTCN-BiGRU-Attention蜣螂算法优化双向时间卷积双向门控循环单元融合注意力机制多变量回归预测效果一览基本介绍模型描述程序…

Vue.js基础指令

&#xff08;在讲指令之前&#xff0c;可以先了解插值表达式&#xff0c;如果已经知道&#xff0c;当我没说&#xff09; 一.插值表达式 1.数据绑定最常见的形式就是双大括号的文本插值&#xff0c;Mustache上属性的值替代。只要绑定的数据对象上属性发生了改变&#xff0c;插…

设置asp.net core WebApi函数请求参数可空的两种方式

以下面定义的asp.net core WebApi函数为例&#xff0c;客户端发送申请时&#xff0c;默认三个参数均为必填项&#xff0c;不填会报错&#xff0c;如下图所示&#xff1a; [HttpGet] public string GetSpecifyValue(string param1,string param2,string param3) {return $"…

【PSINS工具箱】EKF与UKF滤波

描述 对工具箱SINS/GPS&#xff0c;153例程的修改&#xff0c;将EKF和UKF放在一个文件里面&#xff0c;一次运行可以得到两个滤波的结果。 片段 运行截图 程序完整源代码 在有工具箱的情况下&#xff0c;直接运行此代码&#xff0c;即可得到结果 % 基于PSINS工具箱的IMU数据…

腾讯云轻量2核2G3M云服务器优惠价格61元一年,限制200GB月流量

腾讯云轻量2核2G3M云服务器优惠价格61元一年&#xff0c;配置为轻量2核2G、3M带宽、200GB月流量、40GB SSD盘&#xff0c;腾讯云优惠活动 yunfuwuqiba.com/go/txy 活动链接打开如下图&#xff1a; 腾讯云轻量2核2G云服务器优惠价格 腾讯云&#xff1a;轻量应用服务器100%CPU性能…

pyqt 创建右键菜单栏

class MainModule(QMainWindow, Ui_MainWindow):def __init__(self):super().__init__(parentNone)self.setupUi(self)# 允许出现菜单栏self.tableWidget.setContextMenuPolicy(Qt.CustomContextMenu)# 对空间添加右键菜单栏处理 self.tableWidget.customContextMenuRequested.…