Linux(CentOS)/Windows-C++ 云备份项目(服务器网络通信模块,业务处理模块设计,断点续传设计)

此模块将网络通信模块和业务处理模块进行了合并

  1. 网络通信通过httplib库搭建完成
  2. 业务处理:
    • 文件上传请求:备份客户端上传的文件,响应上传成功
    • 客户端列表请求:客户端请求备份文件的请求页面,服务器响应
    • 文件下载请求:通过展示的文件列表,点击下载,服务器响应下载的文件数据

文章目录

  • 1. 网络通信模块设计
  • 2. 业务处理模块设计
    • 文件上传业务处理 /upload请求
    • 展示备份文件页面 / /listshow请求
    • 文件下载业务处理 /download
      • 断点续传原理:
  • 3. 服务器代码:
  • 4. 代码位置

1. 网络通信模块设计

文件下载Http请求部分如下:通过分隔符可以取到文件数据和文件的其他信息,文件信息和文件内容之间空行隔开。这个解析过程httplib库已经封装完毕
在这里插入图片描述

网络通信请求设计:

  1. 文件上传:服务器收到/upload 是为文件上传
  2. 展示页面:服务器收到/listshow是服务器所有备份文件展示
    响应 HTTP/1.1 200 OK + 构造html正文界面
  3. 文件下载:服务器收到/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

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

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

相关文章

os.walk()寻找指定文件

#T2 dcm文件从原位置批量复制到新文件夹F:/467289/ import os import numpy as np path /Users/yxk/Desktop/Debug_test/file# for root, dirs, files in os.walk(path): # for file in files: # if file.endswith(.dcm): # print(file)# def findPa…

android 消息提醒

1.创建 MyBackgroundService.java 继承 Service public class MyBackgroundService extends Service {Overridepublic void onCreate() {super.onCreate();Log.i("业务服务", "开起业务服务");//调用服务后在页面手机上创建一个通知消息。if (android.os…

SQLite数据库浏览器sqlite-web

什么是 sqlite-web &#xff1f; sqlite-web是一个用 Python 编写的基于 Web 的 SQLite 数据库浏览器。 软件特点&#xff1a; 可与您现有的 SQLite 数据库配合使用&#xff0c;也可用于创建新数据库。添加或删除&#xff1a; 表格列&#xff08;支持旧版本的 SQLite&#xff…

VTK 示例 基本的流程-事件交互、球体、

流程可以总结如下&#xff1a; 导入所需的头文件&#xff1a; 首先&#xff0c;导入了一系列 VTK 头文件&#xff0c;这些文件包含了所需的类和函数声明。 创建对象&#xff1a; 创建了两个球体&#xff08;一个较大&#xff0c;一个较小&#xff09;&#xff0c;一个平面&…

未来制造:机器人行业新质生产力提升策略

机器人行业新质生产力提升咨询方案 一、机器人行业目前发展现状及特点&#xff1a; 创新活跃、应用广泛、成长性强。 二、机器人企业发展新质生产力面临的痛点&#xff1a; 1、高端人才匮乏 2、核心技术受限 3、竞争日益国际化 4、成本控制挑战 5、用户体验提升需求 三…

软件杯 深度学习+opencv+python实现车道线检测 - 自动驾驶

文章目录 0 前言1 课题背景2 实现效果3 卷积神经网络3.1卷积层3.2 池化层3.3 激活函数&#xff1a;3.4 全连接层3.5 使用tensorflow中keras模块实现卷积神经网络 4 YOLOV56 数据集处理7 模型训练8 最后 0 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 &am…

pyecharts操作一

pyecharts 是一个用于生成Echarts图表的Python库。Echarts是百度开源的一个数据可视化JS库&#xff0c;可以生成一些非常酷炫的图表。 环境安装 pip install pyecharts 检查版本 import pyecharts print(pyecharts.version) 2.0.3 柱状图绘制 from pyecharts.charts impor…

【论文速读】| 对大语言模型解决攻击性安全挑战的实证评估

本次分享论文为&#xff1a;An Empirical Evaluation of LLMs for Solving Offensive Security Challenges 基本信息 原文作者&#xff1a;Minghao Shao, Boyuan Chen, Sofija Jancheska, Brendan Dolan-Gavitt, Siddharth Garg, Ramesh Karri, Muhammad Shafique 作者单位&a…

设计模式之建造者模式精讲

也叫生成器模式。将一个复杂的构建与它的表示分离&#xff0c;使得同样的构建过程可以创建不同的表示。 在建造者模式中&#xff0c;有如下4个角色&#xff1a; 抽象建造者&#xff08;Builder&#xff09;&#xff1a;用于规范产品的各个组成部分&#xff0c;并进行抽象&…

GEE:将分类特征和标签提取到样本点,并以(csv/shp格式)下载到本地

作者:CSDN @ _养乐多_ 本文将介绍在Google Earth Engine(GEE)平台上,下载用于机器学习分类或者回归的样本点数据,样本点数据携带了分类特征和标签信息,可以以csv格式或者SHP格式。 结果如下图所示, 文章目录 一、核心函数1.1 采样1.2 下载函数二、代码链接三、完整代码…

开源博客项目Blog .NET Core源码学习(12:App.Application项目结构分析)

开源博客项目Blog的App.Application项目主要定义网站页面使用的数据类&#xff0c;同时定义各类数据的增删改查操作接口和实现类。App.Application项目未安装Nuget包&#xff0c;主要引用App.Core项目的类型。   App.Application项目的顶层文件夹如下图所示&#xff0c;下面逐…

Digital Image processing (DIP)

Camera FOV: Filed of view DOV: deep of view 景深 被F f/D 衡量&#xff0c;f 是焦距&#xff0c;D 是光圈大小。 当确定好了景深后&#xff0c;如何光线较暗&#xff0c;则需要补光&#xff0c;或者适当延长曝光时间&#xff08;快门&#xff09; 分辨率、像素尺寸&…

【Linux】详解进程终止进程等待

一、页表&&写时拷贝的进一步理解 页表中不仅仅只有虚拟地址到物理地址的映射&#xff0c;还包括了很多选项&#xff0c;其中就包括了映射条目的权限。当我们进程的代码和数据加载到内存并和进程地址空间建立映射关系时&#xff0c;如果数据的内容不允许被修改&#xff…

linux查找指定目录下包含指定字符串文件,包含子目录

linux查找指定目录下包含指定字符串的文件&#xff0c;包含子目录 linux查找指定目录下包含指定字符串的指定文件格式&#xff0c;包含子目录 指定目录 cd /home/www/linux查找指定目录下包含指定字符串的文件&#xff0c;包含子目录 grep -r "指定字符串"注释 gr…

在 Linux CentOS 中安装 Docker Engine(Dockers 引擎)【图文详解】

官方文档&#xff1a;https://docs.docker.com/engine/install/centos/ 操作系统要求 如果我们要在 CentOS 中安装 Docker 引擎&#xff0c;那么 CentOS 操作系统需要是以下版本之一的&#xff0c;且是处于维护的 CentOS 版本&#xff1a; CentOS 7CentOS Stream 8CentOS Str…

基于Springboot的牙科就诊管理系统(有报告)。Javaee项目,springboot项目。

演示视频&#xff1a; 基于Springboot的牙科就诊管理系统&#xff08;有报告&#xff09;。Javaee项目&#xff0c;springboot项目。 项目介绍: 采用M&#xff08;model&#xff09;V&#xff08;view&#xff09;C&#xff08;controller&#xff09;三层体系结构&#xff0c…

stable diffusion 的 GPU 不足怎么解决

稳定扩散&#xff08;stable diffusion&#xff09;是一种用于图像处理和计算机视觉任务的图像滤波算法。 当使用Stable Diffusion过程中遇到GPU显示内存不足的问题时。解决这个问题的方法有以下几种&#xff1a; 目前&#xff0c;对我来说&#xff0c;就最后一点能够暂时解决当…

显示器接口的了解

显示器视频接口科普&#xff1a;看完就懂HDMI、DP、DVI、VGA、USB-C哪个更适合你的电脑外接显示器_哔哩哔哩_bilibili 电脑显示接口&#xff1a; VGA,DVI,HDMI,DP,USB-C VGA:基本被淘汰了。 常见的还是HDMI1.4和2.0规格 更适合电脑使用的DP接口&#xff08;免费&#xff09;…

笔记本作为其他主机显示屏(HDMI采集器)

前言&#xff1a; 我打算打笔记本作为显示屏来用&#xff0c;连上工控机&#xff0c;这不是贼方便吗 操作&#xff1a; 一、必需品 HDMI采集器一个 可以去绿联买一个&#xff0c;便宜的就行&#xff0c;我的大概就长这样 win10下载 PotPlayer 软件 下载链接&#xff1a;h…

以太网交换——数据链路层

目录 一.以太网工作机制 网卡 交换机工作机制 二.虚拟局域网——vlan划分 1.虚拟局域网 2.怎么区分各个部门&#xff0c;打标签 一.以太网工作机制 早期以太网是同轴电缆连接的&#xff0c;只是传输介质&#xff0c;并不对数据做任何处理。 为解决信号冲突&#xff0c;…