Article directory
- Column introduction
- 1.Business processing implementation ideas
- 2. Network communication interface design
-
- 2.1 File upload request
- 2.2 File list acquisition request
- 2.3 File download request
- 3. Business processing design
- 4. Business processing class implementation and organization
Introduction to the column
About the author: Hua Xiangyun, undergraduate student One, a rising star creator in the C/C++ field, a mentor in the Rising Star Program, an expert blogger at Alibaba Cloud, and a CSDN content partner… dedicated to learning C/C++ and Linux.
Introduction to the column: This article is included in the C + + project – cloud backup
Related column recommendations: C Language Beginner Series, C Language Advanced Series, C++ Series, Data Structures and Algorithms, Linux
Project Gitee link: https://gitee.com/li-yuanjiu/cloud-backup
1. Business processing implementation ideas
In the server-side business processing module, the business processing module and the network communication module are merged
, because the network communication module httplib
library has already been completed for us.
- Build a network communication server:
Use the httplib library to complete
; - Business processing request:
File upload request
: The client uploads the files that need to be backed up – the server responds that the uploaded file is successful;File list request
: The client browser requests a backup file display page – the server responds to the page;File download request
: The client clicks to download the file through the display page – the server responds with the file data that the client wants to download.
2. Network communication interface design
The business processing module needs to process the client's request, so we need to define the communication between the client and the server in advance, clarify what kind of request the client sends, and what kind of response the server should give after processing. This is the design of the network communication interface
.
2.1 File upload request
Client file upload request
POST /upload HTTP/1.1 Content-Length:11 Content-Type: multipart/form-data;boundary= ----WebKitFormBoundary + 16 bytes random characters ------WebKitFormBoundary Content-Disposition: form-data;filename="a.txt"; hello world ------WebKitFormBoundary--
When the server receives the /upload
request of the POST
method, we think it is a file upload request, and after parsing the request (completed by httplib
) , obtain the file data, and write the data into the file (create the corresponding backup file).
Server response
HTTP/1.1 200 OK Content-Length: 0
2.2 File list acquisition request
Client file list view request
GET /list HTTP/1.1 Content-Length: 0
Server response
HTTP/1.1 200 OK Content-Length: Content-Type: text/html <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> <title>Page of Download</title> </head> <body> <h1>Download</h1> <table> <tr> <td><a href="/download/a.txt"> a.txt </a></td> <td align="right"> 1994-07-08 03:00 </td> <td align="right"> 27K </td> </tr> </table> </body> </html>
2.3 File download request
Client file download request
GET /download/a.txt http/1.1 Content-Length: 0
Server response
HTTP/1.1 200 OK Content-Length: 100000 ETags: "filename-size-mtime is a data that uniquely identifies the file" Accept-Ranges: bytes file data
3. Business processing design
The Service
class mainly contains the following members:
class Service {<!-- --> public: Service(); bool RunModule(); // Main logic execution function private: //File upload request processing function static void Upload(const httplib::Request & amp;req, httplib::Response & amp;rsp); //Date formatting function static std::string TimetoStr(time_t t); // Display page request processing function static void ListShow(const httplib::Request & amp;req, httplib::Response & amp;rsp); // Get Etag function static std::string GetETag(const BackupInfo & amp;info); //File download request processing function static void Download(const httplib::Request & amp;req, httplib::Response & amp;rsp); private: int _server_port; // server port std::string _server_ip; // Server IP std::string _download_prefix; // File download request prefix httplib::Server _server; // Server class object is used to build the server };
4. Business processing class implementation and organization
#ifndef __MY_SERVICE__ #define __MY_SERVICE__ #include "util.hpp" #include "config.hpp" #include "data.hpp" #include "httplib.h" extern cloud::DataManager* _data; namespace cloud {<!-- --> class Service {<!-- --> public: Service() {<!-- --> Config* config = Config::GetInstance(); _server_port = config->GetServerPort(); _server_ip = config->GetSeverIp(); _download_prefix = config->GetDownloadPrefix(); } bool RunModule() {<!-- --> _server.Post("/upload", Upload); _server.Get("/listshow", ListShow); _server.Get("/", ListShow); _server.Get("/download/(.*)", Download); _server.listen(_server_ip.c_str(), _server_port); return true; } private: static void Upload(const httplib::Request & amp;req, httplib::Response & amp;rsp) {<!-- --> auto ret = req.has_file("file"); if(ret == false) {<!-- --> rsp.status = 400; return; } const auto & amp; file = req.get_file_value("file"); std::string back_dir = Config::GetInstance()->GetBackDir(); std::string realpath = back_dir + FileUtil(file.filename).FileName(); FileUtil fu(realpath); fu.SetContent(file.content); // Write data to the file BackupInfo info; info.NewBackupInfo(realpath); // Organize backup file information _data->Insert(info); // Add backup file information to the data management module return; } static std::string TimetoStr(time_t t) {<!-- --> std::string tmp = std::ctime( & amp;t); return tmp; } static void ListShow(const httplib::Request & amp;req, httplib::Response & amp;rsp) {<!-- --> // 1. Get the backup information of all files std::vector<BackupInfo> array; _data->GetAll( & amp;array); // 2. Organize html file data based on all backup information std::stringstream ss; ss << "<html><head><title>Download</title></head>"; ss << "<body><h1>Download</h1><table>"; for(auto & a : array) {<!-- --> ss << "<tr>"; std::string filename = FileUtil(a.real_path).FileName(); ss << "<td><a href='" << a.url << "'>" << filename << "</a></td>"; ss << "<td align='right'>" << TimetoStr(a.mtime) << "</td>"; ss << "<td align='right'>" << a.fsize / 1024 << "k</td>"; } ss << "</table></body></html>"; rsp.body = ss.str(); rsp.set_header("Content-Type", "text/html"); rsp.status = 200; } static std::string GetETag(const BackupInfo & amp;info) {<!-- --> // etag: filename-fsize-mtime FileUtil fu(info.real_path); std::string etag = fu.FileName(); etag + = '-'; etag + = std::to_string(info.fsize); etag + = '-'; etag + = std::to_string(info.mtime); return etag; } static void Download(const httplib::Request & amp;req, httplib::Response & amp;rsp) {<!-- --> // 1. Get the path resource requested by the client. If it is compressed, decompress it first. // 2. Obtain file backup information based on the resource path BackupInfo info; _data->GetOneByURL(req.path, & amp;info); // 3. Determine whether the file is compressed. If it is compressed, decompress it first. if(info.pack_flag == true) {<!-- --> FileUtil fu(info.pack_path); fu.UnCompress(info.real_path); // Unzip the file to the backup directory // 4. Delete the compressed package and modify the backup information (no longer compressed) fu.Remove(); info.pack_flag = false; _data->Updata(info); } bool retrans = false; std::string old_etag; if(req.has_header("If-Range")) {<!-- --> old_etag = req.get_header_value("If-Range"); // If there is an If-Range field and the value of this field is consistent with the latest etag of the requested file, it is consistent with breakpoint resumption. if(old_etag == GetETag(info)) {<!-- --> retrans = true; } } // If there is no If-Range field, it is downloaded normally, or if there is this field, but // Its value is inconsistent with the etag of the current file, so all data must be returned // 5. Read the file data and put it into rsp.body FileUtil fu(info.real_path); if(retrans == false) {<!-- --> fu.GetContent( & amp;rsp.body); // 6. Set the corresponding header fields: Etag, Accept-Ranges: bytes rsp.set_header("Accept-Ranges", "bytes"); rsp.set_header("ETag", GetETag(info)); rsp.set_header("Content-Type", "application/octet-stream"); rsp.status = 200; } else {<!-- --> // httplib internally implements the processing of interval requests, that is, breakpoint resume requests. // We only need our users to read all the data of the file into rsp.body, which will automatically adjust the request range internally. // Get the specified interval data from the body to respond // std::string range = req.get_header_value("Range"); bytes=starts-end fu.GetContent( & amp;rsp.body); fu.GetContent( & amp;rsp.body); rsp.set_header("Accept-Ranges", "bytes"); rsp.set_header("ETag", GetETag(info)); // rsq.set_header("Content-Range", "bytes start-end/fsize"); rsp.status = 206; } } private: int _server_port; std::string _server_ip; std::string _download_prefix; httplib::Server _server; }; } #endif