Linux(CentOS)/Windows-C++ 云备份项目(服务器网络通信模块,业务处理模块设计,断点续传设计)
此模块将网络通信模块和业务处理模块进行了合并
- 网络通信通过httplib库搭建完成
- 业务处理:
- 文件上传请求:备份客户端上传的文件,响应上传成功
- 客户端列表请求:客户端请求备份文件的请求页面,服务器响应
- 文件下载请求:通过展示的文件列表,点击下载,服务器响应下载的文件数据
文章目录
- 1. 网络通信模块设计
- 2. 业务处理模块设计
- 文件上传业务处理 /upload请求
- 展示备份文件页面 / /listshow请求
- 文件下载业务处理 /download
- 断点续传原理:
- 3. 服务器代码:
- 4. 代码位置
1. 网络通信模块设计
文件下载Http请求部分如下:通过分隔符可以取到文件数据和文件的其他信息,文件信息和文件内容之间空行隔开。这个解析过程httplib库已经封装完毕
网络通信请求设计:
- 文件上传:服务器收到/upload 是为文件上传
- 展示页面:服务器收到/listshow是服务器所有备份文件展示
响应 HTTP/1.1 200 OK + 构造html正文界面 - 文件下载:服务器收到/download/文件名 为文件下载请求
响应 HTTP/1.1 200 OK +文件数据(正文)
2. 业务处理模块设计
文件上传业务处理 /upload请求
#pragma once
#include "backups.hpp"
#include "./httplib/httplib.h"
#include "./config/config.hpp"
extern CloudBackups::DataMange *dataMange;
namespace CloudBackups
{class Server{private:int port;std::string ip;std::string download_prefix;httplib::Server server;// 上传文件static void Upload(const httplib::Request &request, httplib::Response &response){LOG(INFO, "upload begin");// POST请求,文件数据在http正文中,分区存储bool ret = request.has_file("file"); // 判断有无上传文件字段if (ret == false){LOG(ERROR, "request error!");response.status = 400;return;}// 获取数据const auto &file = request.get_file_value("file");std::string backdir = Config::GetInstance()->GetBackDir();// 保存文件std::string filepath = backdir + FileUtil(file.filename).filename(); // 实际路径+文件名FileUtil stream(filepath);stream.setContent(file.content);// 更新文件信息Json文件BackupInfo info(filepath);dataMange->Insert(info);LOG(INFO, "upload success");}// 展示页面static void ListShow(const httplib::Request &request, httplib::Response &response){}// 下载文件static void Download(const httplib::Request &request, httplib::Response &response){}public:Server(){Config *config = Config::GetInstance();port = config->GetServerPort();ip = config->GetServerIp();download_prefix = config->GetDownloadPrefix();LOG(INFO, "init server success");}bool RunMoudle(){LOG(INFO, "server running");// 搭建Http服务器server.Post("/upload", Upload); // 文件上传server.Get("/list", ListShow); // 展示页面server.Get("/", ListShow); // 网页根目录也是展示页面std::string download_url = download_prefix + "(.*)";server.Get(download_url, Download); // 下载文件,正则表达式捕捉要下载的文件if (server.listen(ip, port) == false){LOG(FATAL, "server listen failed! ip=" + ip);return false;}return true;}};
}
单元测试运行截图
// #include "util/fileutil.hpp"
#include <vector>
#include "util/json.hpp"
#include "config/config.hpp"
#include "backups.hpp"
#include "hot.hpp"
#include "server.hpp"
CloudBackups::DataMange *dataMange;
void ServerUtilTest()
{CloudBackups::Server server;dataMange = new CloudBackups::DataMange();server.RunMoudle();
}
int main(int argc, char const *argv[])
{ServerUtilTest();return 0;
}
上传文件的信息Json如下:
展示备份文件页面 / /listshow请求
#pragma once
#include "backups.hpp"
#include "./httplib/httplib.h"
#include "./config/config.hpp"
extern CloudBackups::DataMange *dataMange;
namespace CloudBackups
{class Server{private:int port;std::string ip;std::string download_prefix;httplib::Server server;// 上传文件static void Upload(const httplib::Request &request, httplib::Response &response){}// 展示页面static void ListShow(const httplib::Request &request, httplib::Response &response){LOG(INFO, "list show begin");// 获取所有文件信息std::vector<BackupInfo> array;dataMange->GetAll(array);// 根据所有文件信息构建http响应std::stringstream ss;ss << R"(<!DOCTYPE html><html lang="cn"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>download list</title></head><body>)";ss << R"(<h1 align="center">Download List</h1>)";for (auto &info : array){std::string filename = FileUtil(info.real_path).filename();ss << R"(<tr><td><a href=")" << info.url << R"(">)" << filename << "</a></td>";ss << R"(<td align="right"> )" << convertTimeStamp2TimeStr(info.mtime) << " </td>";ss << R"(<td align="right">)" << info.size / 1024 << "Kb</td></tr>";ss << "<br>";}ss << "</body></html>";response.body = ss.str();response.set_header("Content-Type", "text/html");response.status = 200;LOG(INFO, "list show end");}// 下载文件static void Download(const httplib::Request &request, httplib::Response &response){}public:Server(){Config *config = Config::GetInstance();port = config->GetServerPort();ip = config->GetServerIp();download_prefix = config->GetDownloadPrefix();LOG(INFO, "init server success");}bool RunMoudle(){LOG(INFO, "server running");// 搭建Http服务器server.Post("/upload", Upload); // 文件上传server.Get("/list", ListShow); // 展示页面server.Get("/", ListShow); // 网页根目录也是展示页面std::string download_url = download_prefix + "(.*)";server.Get(download_url, Download); // 下载文件,正则表达式捕捉要下载的文件if (server.listen(ip, port) == false){LOG(FATAL, "server listen failed! ip=" + ip);return false;}return true;}};
}
文件下载业务处理 /download
http的ETag头部字段:存储了一个资源的唯一标识
客户端第一次请求文件时会收到响应信息。
客户端第二次下载时,客户端会把这个信息发送给服务器,让这个服务器根据这个标识判断这个资源有没有被修改锅。如果没修改过。客户端直接使用缓存区的资源。如果改过则重新修改
http对ETag字段没有定义,这里设定:
ETags:文件名称-文件大小-最后修改时间 构成
ETags字段也用于断点续传,断点续传也需要保证文件没有被修改
http协议的Accept-Ranges:bytes字段用于表示支持断点续传。数据以字节结尾
Content-Type:字段决定了浏览器如何处理响应正文,用来区分下载还是html显示。
Content-Type:application/octet-stream常用于文件下载
断点续传原理:
文件下载时由于异常而中断,如果从头下载效率较低,需要将之前传输过的数据效率太低。断点续传的目的为了提高上传效率
实现:客户端在下载时需要记录当前下载的位置。当下载中断时,下次断点续传时将下载起始位置发送给服务器。服务器收到后仅仅回传客户端需要的数据即可
如果下载文件后这个文件在服务器上被修改了,这时候需要将文件重新下载
http中断点续传关键点在于告诉服务器下载区间范围,服务器上要检测这个文件是否被修改。
http协议的Accept-Ranges:bytes字段用于表示支持断点续传
ETag文件唯一标识符,客户端收到响应会保存这个信息
请求:
GET /download/test.txt HTTP/1.1
If-Range:“服务端在下载时响应ETag字段搭配使用判断文件是否被修改,常用于恢复下载”
Range: bytes=100-200(区间范围) 这个字段用来告诉客户端需要的数据范围
响应:
HTTP/1.1 206(服务器处理部分get请求) Paritial Content
ETag:”xxxx“(响应资源的版本标识符,判断文件是否被修改)
Content-Range: bytes 100-200(范围)
Accept-Ranges: bytes 字段用于表示支持断点续传正文就是对应区间的数据
真正实现时:cpp-httplib会自动根据请求Range字段对response.body进行切片返回,封装实现。直接把response.body全部设置为文件所有内容即可
#pragma once
#include "backups.hpp"
#include "../httplib/httplib.h"
#include "../config/config.hpp"
extern CloudBackups::DataMange *dataMange;
namespace CloudBackups
{class Server{private:int port;std::string ip;std::string download_prefix;httplib::Server server;// ETag为设计者自行指定 ETags:文件名称-文件大小-最后修改时间 构成static std::string GetETag(BackupInfo info){std::string etag = FileUtil(info.real_path).filename();etag += "-";etag += std::to_string(info.size);etag += "-";etag += std::to_string(info.mtime);return etag;}// 下载文件static void Download(const httplib::Request &request, httplib::Response &response){// 1. 获取客户端请求资源的路径 request.path// 2. 根据路径获取文件备份信息BackupInfo info;if (dataMange->GetByUrl(request.path, info) == false){LOG(WARNING, "file /download not found");response.status = 404;return;}// 3. 判断文件是否被压缩,被压缩的话需要先解压缩,删除压缩包,修改备份信息if (info.packflag == true){// 被压缩,解压到backdir目录浏览FileUtil tool(info.pack_path);tool.unzip(info.real_path);// 删除压缩包tool.removeFile();info.packflag = false;// 修改配置文件dataMange->UpDate(info);}// 4. 读取文件数据放入body中FileUtil tool(info.real_path);tool.getContent(response.body);// 判断断点续传bool retrans = false; // 标记断点续传std::string befetag;if (request.has_header("If-Range")){// 断点续传 服务端在下载时响应ETag字段搭配使用判断文件是否被修改befetag = request.get_header_value("If-Range");if (befetag == GetETag(info)){// 文件没修改过retrans = true;}}// 没有If-Range字段或者If-Range字段与ETag不匹配,重新下载if (retrans == false){// 正常下载// 5. 设置响应头部字段ETag Accept-Range字段response.set_header("ETag", GetETag(info));response.set_header("Accept-Ranges", "bytes");response.set_header("Content-Type", "application/octet-stream");response.status = 200;}else{// 断点续传,了解区间范围response.set_header("ETag", GetETag(info));response.set_header("Accept-Ranges", "bytes");response.status = 206; // cpp-httplib会自动根据请求Range字段对response.body进行切片返回,封装实现}LOG(INFO, "download success");}public:Server(){Config *config = Config::GetInstance();port = config->GetServerPort();ip = config->GetServerIp();download_prefix = config->GetDownloadPrefix();// 创建文件夹FileUtil tool;tool.mkdir(Config::GetInstance()->GetBackDir());tool.mkdir(Config::GetInstance()->GetPackfileDir());LOG(INFO, "init server success");}bool RunMoudle(){LOG(INFO, "server running");// 搭建Http服务器server.Post("/upload", Upload); // 文件上传server.Get("/list", ListShow); // 展示页面server.Get("/", ListShow); // 网页根目录也是展示页面std::string download_url = download_prefix + "(.*)";// LOG(INFO, "DEBUG:" + download_url);server.Get(download_url, Download); // 下载文件,正则表达式捕捉要下载的文件if (server.listen(ip, port) == false){LOG(FATAL, "server listen failed! ip=" + ip);return false;}return true;}};
}
3. 服务器代码:
#include <vector>
#include "../util/json.hpp"
#include "../config/config.hpp"
#include "backups.hpp"
#include "hot.hpp"
#include "server.hpp"
#include <thread>
CloudBackups::DataMange *dataMange;
void ServerRun()
{CloudBackups::Server server;dataMange = new CloudBackups::DataMange();server.RunMoudle();
}
void HotRun()
{dataMange = new CloudBackups::DataMange();CloudBackups::HotMange hot;hot.RunModule();
}
int main(int argc, char const *argv[])
{// 启动热点管理模块std::thread hot_thread(HotRun);std::thread server_thread(ServerRun);hot_thread.join();server_thread.join();return 0;
}
4. 代码位置
至此,项目服务器所有业务处理完毕
Gitee
Github
相关文章:
Linux(CentOS)/Windows-C++ 云备份项目(服务器网络通信模块,业务处理模块设计,断点续传设计)
此模块将网络通信模块和业务处理模块进行了合并 网络通信通过httplib库搭建完成业务处理: 文件上传请求:备份客户端上传的文件,响应上传成功客户端列表请求:客户端请求备份文件的请求页面,服务器响应文件下载请求&…...
【QQ版】QQ群短剧机器人源码 全网短剧机器人插件
内容目录 一、详细介绍二、效果展示2.效果图展示 三、学习资料下载 一、详细介绍 QQ版本可以兼容两个框架(HTQQ,MYQQ这两个的vip版也可以使用) 支持私聊与群聊,命令是 搜剧影视关键词 如果无法搜索到影视资源,请使用下方命令&…...
矩阵间关系的建立
参考文献 2-D Compressive Sensing-Based Visually Secure Multilevel Image Encryption Scheme 加密整体流程如下: 我们关注左上角这一部分: 如何在两个图像之间构建关系,当然是借助第3个矩阵。 A. Establish Relationships Between Different Images 简单说明如下: …...
【C++】C到C++的入门知识
目录 1、C关键字 2、命名空间 2.1 命名空间的定义 2.2 命名空间的使用 2.2.1 加命名空间名称及作用域限定符 2.2.2 使用using将命名空间中某个成员引入 2.2.3 使用using namespace 命名空间名称引入 3、C输入&输出 4、缺省参数 4.1 缺省参数的概念 4.2 缺省参数的…...
【c++】简单的日期计算器
🔥个人主页:Quitecoder 🔥专栏:c笔记仓 朋友们大家好啊,在我们学习了默认成员函数后,我们本节内容来完成知识的实践,来实现一个简易的日期计算器 目录 头文件声明函数函数的实现1.全缺省默认构…...
基于easyx库的C/C++游戏编程实例-飞机大战
飞机大战游戏设计 首先创建飞机/子弹结构: struct Plane {int x;int y;bool live;int width;int height;int type;int hp; }player,bul[BUL_NUM],enemy[ENE_NUM];你需要加载图片: void ImageLoad() {//背景loadimage(&bg[0], "./image/飞机大…...
stitcher类实现多图自动拼接
效果展示 第一组: 第二组: 第三组: 第四组: 运行代码 import os import sys import cv2 import numpy as npdef Stitch(imgs,savePath): stitcher cv2.Stitcher.create(cv2.Stitcher_PANORAMA)(result, pano) stitcher.st…...
Ubuntu下udp通信
一、知识准备阶段 socket是什么?套接字是什么? https://blog.csdn.net/m0_37925202/article/details/80286946 Socket程序从Windows移植到Linux下的一些注意事项 sockaddr和sockaddr_in详解 bzero和memset函数 函数原型:void bzero&…...
拌合楼管理软件开发(十三) 对接耀华XK3190-A9地磅(实战篇)
前言: 实战开整 目前而言对于整个拌合楼管理软件开发,因为公司对这个项目还处于讨论中,包括个人对其中的商业逻辑也存在一些质疑,都是在做一些技术上的储备.很早就写好了串口与地磅对接获取代码,也大概知道真个逻辑,这次刚好跟库区沟通,远程连接到磅房电脑,开始实操一下. 一、地…...
FastAPI+React全栈开发10 MongoDB聚合查询
Chapter02 Setting Up the Document Store with MongoDB 10 Aggregation framework FastAPIReact全栈开发10 MongoDB聚合查询 In the following pages, we will try to provide a brief introducton to the MongoDB aggregation framework, what it is, what benefits it of…...
python 报错问题汇总
error: [WinError 32] 另一个程序正在使用此文件,进程无法访问。: d:\\anaconda\\envs\\yolov5\\lib\\site-packages\\ISR-2.2.0-py3.7.egg 解决方法:重启pycharm python-contrib 无法安装 opencv-contrib-python 安装包网址:安装包下载链接…...
6.5物联网RK3399项目开发实录-驱动开发之LCD显示屏使用(wulianjishu666)
90款行业常用传感器单片机程序及资料【stm32,stc89c52,arduino适用】 链接:https://pan.baidu.com/s/1M3u8lcznKuXfN8NRoLYtTA?pwdc53f LCD使用 简介 AIO-3399J开发板外置了两个LCD屏接口,一个是EDP,一个是LVDS,接口对应板…...
「Android高级工程师」BAT大厂面试基础题集合-下-Github标星6-5K
C、 com.android.provider.contact D、 com.android.provider.contacts 11.下面关于ContentProvider描述错误的是()。 A、 ContentProvider可以暴露数据 B、 ContentProvider用于实现跨程序共享数据 C、 ContentProvider不是四大组件 D、 ContentP…...
【算法】基数排序
简介 基数排序(*Radix sort)是一种非比较排序算法(non-comparative sorting algorithm)。现代计算机的基数排序算法由 计数排序 算法的开发人哈罗德H西华德(Harold H. Seward)于1954年于麻省理工大学开发。…...
2核2G服务器优惠价格轻量61元一年,CVM价格313元15个月
腾讯云2核2G服务器多少钱一年?轻量服务器61元一年,CVM 2核2G S5服务器313.2元15个月,轻量2核2G3M带宽、40系统盘,云服务器CVM S5实例是2核2G、50G系统盘。腾讯云2核2G服务器优惠活动 txybk.com/go/txy 链接打开如下图:…...
不同Python版本和wxPython版本用pyinstaller打包文件大小对比
1、确定wxPython和Python版本的对应关系 在这里可以找到Python支持的所有wxPython版本:https://pypi.tuna.tsinghua.edu.cn/simple/wxpython/ 由于Python从3.6版本开始支持f字符串、从3.9版本开始不支持Windows7操作系统,所以我仅筛选3.6-3.8之间的版本…...
【C语言】结构体详解(一)
目录 1、什么是结构体? 2、结构体成分 3、结构体变量的定义与初始化 3.1、结构体变量的三种定义方式 3.2、结构体变量的初始化 4、结构体成员的访问(两种方式) 4.1、直接访问 4.2、间接访问 5、结构的特殊声明 5.1、不完全声明(匿…...
AI时代-普通人的AI绘画工具对比(Midjouney与Stable Diffusion)
AI时代-普通人的AI绘画工具对比(Midjouney与Stable Diffusion) 前言1、基础对比Stable Diffusion(SD)SD界面安装与使用SD Midjouney(MJ) 2、硬件与运行要求对比Stable Diffusion硬件要求内存硬盘显卡 Midjo…...
【蓝桥杯】矩阵快速幂
一.快速幂概述 1.引例 1)题目描述: 求A^B的最后三位数表示的整数,A^B表示:A的B次方。 2)思路: 一般的思路是:求出A的B次幂,再取结果的最后三位数。但是由于计算机能够表示的数字…...
C语言使用STM32开发板手搓高端家居洗衣机
目录 概要 成品效果 背景概述 1.开发环境 2.主要传感器。 技术细节 1. 用户如何知道选择了何种功能 2.启动后如何进行洗衣 3.如何将洗衣机状态上传至服务器并通过APP查看 4.洗衣过程、可燃气检测、OLED屏显示、服务器通信如何并发进行 小结 概要 本文章主要是讲解如…...
【Hello,PyQt】QTextEdit和QSplider
PyQt5 是一个强大的Python库,用于创建图形用户界面(GUI)。其中,QTextEdit 控件作为一个灵活多用的组件,常用于显示和编辑多行文本内容,支持丰富的格式设置和文本操作功能。另外,QSlider 控件是一…...
【力扣】191.位 1 的个数、485.最大连续 1 的个数
191.位 1 的个数 题目描述 编写一个函数,输入是一个无符号整数(以二进制串的形式),返回其二进制表达式中 设置位 的个数(也被称为汉明重量)。 示例 1: 输入:n 11 输出࿱…...
蓝桥杯 java 承压计算
题目: 思路: 1:其中的数字代表金属块的重量(计量单位较大) 说明每个数字后面不一定有多少个0 2:假设每块原料的重量都十分精确地平均落在下方的两个金属块上,最后,所有的金属块的重量都严格精确地平分落在最底层的电子…...
leetcode268-Missing Number
这道题目要求缺失的数字,一般解决数组的问题,要么往排序数组,要么往双指针遍历这些方向上靠,要么往异或方向上靠,总之落点无非就只有这几个。我们要求缺失的数字,可以依次让1~n和数组元素进行异…...
【jenkins+cmake+svn管理c++项目】jenkins回传文件到svn(windows)
书接上文:创建一个项目 在经过cmakemsbuild顺利生成动态库之后,考虑到我一个项目可能会生成多个动态库,它们分散在build内的不同文件夹,我希望能将它们收拢到一个文件夹下,并将其回传到svn。 一、动态库移位—cmake实…...
数据结构·二叉树(2)
目录 1 堆的概念 2 堆的实现 2.1 堆的初始化和销毁 2.2 获取堆顶数据和堆的判空 2.3 堆的向上调整算法 2.4 堆的向下调整算法 2.4 堆的插入 2.5 删除堆顶数据 2.6 建堆 3 建堆的时间复杂度 3.1 向上建堆的时间复杂度 3.2向下建堆的时间复杂度 4 堆的排序 前言&…...
MATLAB算法实战应用案例精讲-【毕业季论文专用】人工智能视觉检测技术及其在实际应用中的挑战与前景
目录 摘要: 第一章:引言 1.1 研究背景 1.2 研究目的与意义...
Linux虚拟机环境搭建spark
Linux环境搭建Spark分为两个版本,分别是Scala版本和Python版本。 一、 安装Pyspark 本环境以 Python 环境为例。 1、下载spark 下载网址:https://archive.apache.org/dist/spark 下载安装包:根据自己环境选择合适版本,本环境…...
STL的string容器
string基本概念 string是C风格的字符串,本质上是一个类。 string 和 char* 的区别 char* 是一个指针; string是一个类,内部封装了 char* ,用来管理字符串,是一个 char* 型的容器。 特点 string内部封装了很多成员…...
半导体工艺技术
完整内容点击:【半导体工艺技术】...
嘉善网站建设jswebs/色盲测试图片
发布一个k8s部署视频:https://edu.csdn.net/course/detail/26967 课程内容:各种k8s部署方式。包括minikube部署,kubeadm部署,kubeasz部署,rancher部署,k3s部署。包括开发测试环境部署k8s,和生产…...
机关网站机制建设情况/seo优化包括
寄生组合式继承 定义:所谓寄生组合式继承,即通过借用构造函数来继承属性,通过原型链的混成形式来继承方法。其背后的基本思路是:不必为了指定子类型的原型而调用超类型的构造函数,我们所需要的无非就是超类型原型的一…...
化妆培训学校网站开发/seo建站优化推广
谈到企业级自助分析平台,大家自然会想到Tableau,在Garnter最新的BI平台魔力象限中,是这么描述Tableau的。 “Tableau is a Leader in this Magic Quadrant. It offers a visual-based exploration experience that enables business users to…...
上海专业网站建设/中国疫情最新数据
1. 问题引入——频率的稳定值记为概率,这里的“稳定”是何含义? 2. 依概率收敛的定义 3. 依概率收敛示例 4. 依概率收敛的性质 5. 切比雪夫不等式(定理)及其证明 6. 切比雪夫不等式的适用范围 7. 切比雪夫不等式的应用示例...
哈尔滨网站建设渠道/谷歌chrome浏览器
1、克隆远程仓库 git clone [仓库地址] ,但是这样只能克隆master分支的代码,如果我想克隆远程仓库中某一分支的代码怎么办呢?git clone -b [对应的远程分支名称] [仓库地址] 。如克隆aspnetcore的3.0分支:git clone -b 3.0 https:…...
做网批有专门的网站吗?/百度快照投诉中心官网
下载 官方下载地址,要注意的是要下载的是 MySQL Community Server。根据系统选择相应压缩包,这个是 win 下安装。选择 Zip Archive 安装 将下载好的压缩包解压到想要安装的文件夹即可,我的是 C:/mysql 配置 配置环境变量 增加系统环境变量: M…...