做时时网站要多少钱,企业廉洁建设,公司文化墙图片大全,免费制作二级网站此模块将网络通信模块和业务处理模块进行了合并
网络通信通过httplib库搭建完成业务处理#xff1a; 文件上传请求#xff1a;备份客户端上传的文件#xff0c;响应上传成功客户端列表请求#xff1a;客户端请求备份文件的请求页面#xff0c;服务器响应文件下载请求 文件上传请求备份客户端上传的文件响应上传成功客户端列表请求客户端请求备份文件的请求页面服务器响应文件下载请求通过展示的文件列表点击下载服务器响应下载的文件数据 文章目录 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::vectorBackupInfo array;dataMange-GetAll(array);// 根据所有文件信息构建http响应std::stringstream ss;ss R(!DOCTYPE htmlhtml langcnheadmeta charsetUTF-8meta nameviewport contentwidthdevice-width, initial-scale1.0titledownload list/title/headbody);ss R(h1 aligncenterDownload List/h1);for (auto info : array){std::string filename FileUtil(info.real_path).filename();ss R(trtda href) info.url R() filename /a/td;ss R(td alignright ) convertTimeStamp2TimeStr(info.mtime) /td;ss R(td alignright) 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-Typeapplication/octet-stream常用于文件下载
断点续传原理
文件下载时由于异常而中断如果从头下载效率较低需要将之前传输过的数据效率太低。断点续传的目的为了提高上传效率
实现客户端在下载时需要记录当前下载的位置。当下载中断时下次断点续传时将下载起始位置发送给服务器。服务器收到后仅仅回传客户端需要的数据即可
如果下载文件后这个文件在服务器上被修改了这时候需要将文件重新下载
http中断点续传关键点在于告诉服务器下载区间范围服务器上要检测这个文件是否被修改。 http协议的Accept-Ranges:bytes字段用于表示支持断点续传 ETag文件唯一标识符客户端收到响应会保存这个信息
请求 GET /download/test.txt HTTP/1.1 If-Range:“服务端在下载时响应ETag字段搭配使用判断文件是否被修改常用于恢复下载” Range: bytes100-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