买完服务器怎么做网站,crm客户关系管理系统源码,怎么做自己淘宝优惠券网站,谷歌chrome浏览器下载云备份项目
1. 云备份认识
自动将本地计算机上指定文件夹中需要备份的文件上传备份到服务器中。并且能够随时通过浏览器进行查看并且下载#xff0c;其中下载过程支持断点续传功能#xff0c;而服务器也会对上传文件进行热点管理#xff0c;将非热点文件进行压缩存储…云备份项目
1. 云备份认识
自动将本地计算机上指定文件夹中需要备份的文件上传备份到服务器中。并且能够随时通过浏览器进行查看并且下载其中下载过程支持断点续传功能而服务器也会对上传文件进行热点管理将非热点文件进行压缩存储节省磁盘空间。
2. 实现目标
这个云备份项目需要我们实现两端程序其中包括部署在用户机的客户端程序上传需要备份的文件以及运行在服务器上的服务端程序实现备份文件的存储和管理两端合作实现总体的自动云备份功能。
3. 功能划分
3.1 服务端
3.1.1 服务端程序负责功能
针对客户端上传的文件进行备份存储能够对文件进行热点文件管理对非热点文件进行压缩存储节省磁盘空间。支持客户端浏览器查看访问文件列表。支持客户端浏览器下载文件并且下载支持断点续传。
3.1.2. 服务端功能模块划分
数据管理模块负责服务器上备份文件的信息管理。网络通信模块搭建网络通信服务器实现与客户端通信。业务处理模块针对客户端的各个请求进行对应业务处理并响应结果。热点管理模块负责文件的热点判断以及非热点文件的压缩存储。
3.2 客户端
3.2.1 客户端程序负责功能
能够自动检测客户机指定文件夹中的文件并判断是否需要备份将需要备份的文件逐个上传到服务器
3.2.2 客户端功能模块划分
数据管理模块负责客户端备份的文件信息管理通过这些数据可以确定一个文件是否需要备份。文件检测模块遍历获取指定文件夹中所有文件路径名称。网络通信模块搭建网络通信客户端实现将文件数据备份上传到服务器。
4. 第三方库
4.1 jsoncpp
json是一种数据交换格式采用完全独立于编程语言的文本格式来存储和表示数据。
json数据类型对象使用花括号{}括起来的表示一个对象。数组使用中括号[]括起来的表示一个数组。字符串使用常规双引号括起来的表示一个字符串。数字包括整形和浮点型直接使用。
例如小明同学的学生信息
char name 小明;
int age 18;
float score[3] {88.5, 99, 58};
则json这种数据交换格式是将这多种数据对象组织成为一个字符串
[{姓名 : 小明,年龄 : 18,成绩 : [88.5, 99, 58]},{姓名 : 小黑,年龄 : 18,成绩 : [88.5, 99, 58]}
]jsoncpp库用于实现json格式的序列化和反序列化完成将多个数据对象组织成为json格式字符串以及将json格式字符串解析得到多个数据对象的功能。
这其中主要借助三个类以及其对应的少量成员函数完成
//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;
}4.2 bundle数据压缩库
GitHub链接
BundleBundle是一个嵌入式压缩库支持23种压缩算法和2种存档格式。使用的时候只需要加入两个文件bundle.h 和 bundle.cpp即可。
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 );
}4.3. httplib库
GitHub链接
httplib库一个C11单文件头的跨平台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::vectorMultipartFormData;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::functionvoid(const Request , Response );using Handlers std::vectorstd::pairstd::regex, Handler;std::functionTaskQueue *(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);}
}5. 服务端工具类实现
5.1 文件实用工具类设计
不管是客户端还是服务端文件的传输备份都涉及到文件的读写包括数据管理信息的持久化也是如此因此首先设计封装文件操作类这个类封装完毕之后则在任意模块中对文件进行操作时都将变的简单化。
C17中filesystem手册
/*util.hpp*/
class FileUtil{private:std::string _name;public:FileUtil(const std::string name);size_t FileSize();time_t LastATime();time_t LastMTime();std::string FileName();bool GetPosLen(std::string *content, size_t pos, size_t len);bool GetContent(std::string *content);bool SetContent(std::strint *content);bool Compress(const std::string packname);bool UnCompress(const std::string filename);bool Exists();bool CreateDirectory();bool ScanDirectory(std::vectorstd::string *arry);
};5.2 json实用工具类设计
/*util.hpp*/
class JsonUtil{public:static bool Serialize(const Json::Value root, std::string *str);static bool UnSerialize(const std::string str, Json::Value *root);
};6. 服务端配置信息模块实现
6.1 系统配置信息
使用文件配置加载一些程序的运行关键信息可以让程序的运行更加灵活。
配置信息
热点判断时间文件下载URL前缀路径压缩包后缀名称上传文件存放路径压缩文件存放路径服务端备份信息存放文件服务器访问IP地址服务器访问端口
{hot_time : 30,server_port : 8888,server_ip : 172.19.54.175, download_prefix : /download/,packfile_suffix : .lz,pack_dir : ./packdir/,back_dir : ./backdir/,backup_file : ./cloud.dat
}6.2 单例文件配置类设计
使用单例模式管理系统配置信息能够让配置信息的管理控制更加统一灵活。
#define CONFIG_FILE ./cloud.conf
#ifndef __M_CONFIG_H__
#define __M_CONFIG_H__
#include mutex
#include util.hpp
namespace cloud
{class Config{private:Config(){}static Config *_instance;static std::mutex _mutex;private:int _hot_time; // 热点判断时间int _server_port; // 服务器监听端口std::string _server_ip; // 服务器IP地址std::string _download_prefix; // 下载url前缀路径std::string _packfile_suffix; // 压缩包后缀名称std::string _pack_dir; // 压缩包存放目录std::string _back_dir; // 备份文件存放目录std::string _backup_file; // 数据信息存放文件bool ReadConfigFile(){}public:static Config *GetInstance(){}int GetHotTime(){}int GetServerPort(){}std::string GetServerIP(){}std::string GetDownloadPrefix(){}std::string GetPackFileSuffix(){}std::string GetPackDir(){}std::string GetBackDir(){}std::string GetBackupFile(){}};Config *Config::_instance nullptr;std::mutex Config::_mutex;
}
#endif6.3 管理的数据信息
文件实际存储路径文件是否压缩标志压缩包存储路径文件访问URL文件最后一次修改时间文件最后一次访问时间文件大小
6.4 如何管理数据
内存中以文件访问URL为key数据信息结构为val使用哈希表进行管理查询速度快。使用url作为key是因为往后客户端浏览器下载文件的时候总是以url作为请求。采用文件形式对数据进行持久化存储序列化方式采用json格式或者自定义方式
6.5 数据管理类的设计
/*data.hpp*/
#ifndef __M_DATA_H__
#define __M_DATA_H__
#include unordered_map
#include pthread.h
#include util.hpp
#include config.hpp
namespace cloud
{typedef struct BackupInfo{bool pack_flag; // 是否压缩标志size_t fsize; // 文件大小time_t atime; // 最后一次访问时间time_t mtime; // 最后一次更改时间std::string real_path; // 文件实际存储路径std::string pack_path; // 压缩文件储存路径std::string url_path; //bool NewBackupInfo(const std::string realpath){} } BackupInfo;class DataManager{public:DataManager(){}~DataManager(){} bool Insert(const BackupInfo info){} bool Update(const BackupInfo info){} bool GetOneByURL(const std::string url, BackupInfo *info){}bool GetOneByRealPath(const std::string realpath, BackupInfo *info){}bool GetAll(std::vectorBackupInfo *array){} bool Storage(){}bool InitLoad(){}private:std::string _backup_file;pthread_rwlock_t _rwlock; // 读写锁 - 读共享写互斥std::unordered_mapstd::string, BackupInfo _table;};
}
#endif7. 服务端热点管理模块实现
7.1 热点管理实现思路
服务器端的热点文件管理是对上传的非热点文件进行压缩存储节省磁盘空间。
而热点文件的判断在于上传的文件的最后一次访问时间是否在热点判断时间之内比如如果一个文件一天都没有被访问过我们就认为这是一个非热点文件其实就是当前系统时间与文件最后一次访问时间之间的时间差是否在一天之内的判断。
而我们需要对上传的文件每隔一段时间进行热点检测相当于遍历上传文件的存储文件夹找出所有的文件然后通过对逐个文件进行时间差的判断来逐个进行热点处理。
基于这个思想我们需要将上传的文件存储位置与压缩后压缩文件的存储位置分开。这样在遍历上传文件夹的时候不至于将压缩过的文件又进行非热点处理了。
关键点
上传文件有自己的上传存储位置非热点文件的压缩存储有自己的存储位置遍历上传存储位置文件夹获取所有文件信息。获取每个文件最后一次访问时间进而完成是否热点文件的判断。对非热点文件进行压缩存储删除原来的未压缩文件。
7.2 热点管理类的设计
#ifndef __M_HOT_H__
#define __M_HOT_H__
#include unistd.h
#include data.hpp
//因为数据管理是要在多个模块中访问的因此将其作为全局数据定义在此处声明使用即可
extern cloud::DataManager *_data;
namespace cloud
{class HotManager{public:HotManager(){}bool RunModule(){} private:// 非热点文件-假 热点文件-真bool HotJudge(const std::string filename){}private:std::string _back_dir;std::string _pack_dir;std::string _pack_suffix;int _hot_time;};
}
#endif8. 服务端业务处理模块实现
8.1 业务处理实现思路
云备份项目中 业务处理模块是针对客户端的业务请求进行处理并最终给与响应。而整个过程中包含以下要实现的功能
借助网络通信模块httplib库搭建http服务器与客户端进行网络通信针对收到的请求进行对应的业务处理并进行响应文件上传列表查看文件下载包含断点续传
8.2 网络通信接口设计
业务处理模块要对客户端的请求进行处理那么我们就需要提前定义好客户端与服务端的通信明确客户端发送什么样的请求服务端处理后应该给与什么样的响应而这就是网络通信接口的设计。
HTTP文件上传
POST /upload HTTP/1.1
Content-Length11
Content-Typemultipart/form-data;boundary ----WebKitFormBoundary16字节随机字符
------WebKitFormBoundary
Content-Dispositionform-data;filenamea.txt
hello world
------WebKitFormBoundary--HTTP/1.1 200 OK
Content-Length: 0HTTP文件列表获取
GET /list HTTP/1.1
Content-Length: 0HTTP/1.1 200 OK
Content-Length:
Content-Type: text/htmlhtmlheadmeta http-equivContent-Type contenttext/html; charsetUTF-8 /titlePage of Download/title/headbodyh1Download/h1tabletrtda href/download/a.txt a.txt /a/tdtd alignright 1994-07-08 03:00 /tdtd alignright 27K /td/tr/table/body
/htmlHTTP文件下载
GET /download/a.txt http/1.1
Content-Length: 0HTTP/1.1 200 OK
Content-Length: 100000
ETags: filename-size-mtime一个能够唯一标识文件的数据
Accept-Ranges: bytes文件数据HTTP断点续传
GET /download/a.txt http/1.1
Content-Length: 0
If-Range: 文件唯一标识
Range: bytes89-999HTTP/1.1 206 Partial Content
Content-Length:
Content-Range: bytes 89-999/100000
Content-Type: application/octet-stream
ETag: inode-size-mtime一个能够唯一标识文件的数据
Accept-Ranges: bytes对应文件从89到999字节的数据。8.3 业务处理类设计
//因为业务处理的回调函数没有传入参数的地方因此无法直接访问外部的数据管理模块数据
//可以使用lamda表达式解决但是所有的业务功能都要在一个函数内实现于功能划分上模块不够清晰
//因此将数据管理模块的对象定义为全局数据,在这里声明一下就可以在任意位置访问了
#ifndef __M_SERVICE_H__
#define __M_SERVICE_H__
#include sstream
#include data.hpp
#include httplib.h
extern cloud::DataManager *_data;
namespace cloud
{class Service{public:Service(){} bool RunModule(){} private:static void Upload(const httplib::Request req, httplib::Response rsp){} // 静态成员函数不能调用非静态成员函数 -- 没有this指针static std::string TimetoStr(time_t t){} static void ListShow(const httplib::Request req, httplib::Response rsp){} static std::string GetETag(const BackupInfo info){} static void Download(const httplib::Request req, httplib::Response rsp){}private:std::string _server_ip; // IP地址int _server_port; // 端口号std::string _download_prefix; // 下载前缀httplib::Server _server; // http对象};
}
#endif9. 客户端数据管理模块实现
9.1 数据信息设计
客户端要实现的功能是对指定文件夹中的文件自动进行备份上传。但是并不是所有的文件每次都需要上传我们需要能够判断哪些文件需要上传哪些不需要因此需要将备份的文件信息给管理起来作为下一次文件是否需要备份的判断。因此需要被管理的信息包含以下
文件路径名称文件唯一标识由文件名最后一次修改时间文件大小组成的一串信息
9.2 文件操作实用类设计
这个其实与服务端的文件实用工具类雷同只是功能需求并没有服务端那么多。
#ifndef __M_SERVICE_H__
#define __M_SERVICE_H__
#include sstream
#include data.hpp
#include httplib.h
extern cloud::DataManager *_data;
namespace cloud
{class Service{public:Service(){} bool RunModule(){}private:static void Upload(const httplib::Request req, httplib::Response rsp){}// 静态成员函数不能调用非静态成员函数 -- 没有this指针static std::string TimetoStr(time_t t){} static void ListShow(const httplib::Request req, httplib::Response rsp){}static std::string GetETag(const BackupInfo info){}static void Download(const httplib::Request req, httplib::Response rsp){}private:std::string _server_ip; // IP地址int _server_port; // 端口号std::string _download_prefix; // 下载前缀httplib::Server _server; // http对象};
}
#endif9.3 数据管理类设计
#ifndef __M_SERVICE_H__
#define __M_SERVICE_H__
#include sstream
#include data.hpp
#include httplib.h
extern cloud::DataManager *_data;
namespace cloud
{class Service{public:Service(){} bool RunModule(){} private:static void Upload(const httplib::Request req, httplib::Response rsp){}// 静态成员函数不能调用非静态成员函数 -- 没有this指针static std::string TimetoStr(time_t t)static void ListShow(const httplib::Request req, httplib::Response rsp){}static std::string GetETag(const BackupInfo info){} static void Download(const httplib::Request req, httplib::Response rsp){}private:std::string _server_ip; // IP地址int _server_port; // 端口号std::string _download_prefix; // 下载前缀httplib::Server _server; // http对象};
}
#endif9.4 文件备份类设计
#ifndef __M_SERVICE_H__
#define __M_SERVICE_H__
#include sstream
#include data.hpp
#include httplib.h
extern cloud::DataManager *_data;
namespace cloud
{class Service{public:Service(){}bool RunModule(){}private:static void Upload(const httplib::Request req, httplib::Response rsp){}// 静态成员函数不能调用非静态成员函数 -- 没有this指针static std::string TimetoStr(time_t t)static void ListShow(const httplib::Request req, httplib::Response rsp){}static std::string GetETag(const BackupInfo info){}static void Download(const httplib::Request req, httplib::Response rsp){}private:std::string _server_ip; // IP地址int _server_port; // 端口号std::string _download_prefix; // 下载前缀httplib::Server _server; // http对象};
}
#endif10. 项目总结
项目名称云备份系统
项目功能搭建云备份服务器与客户端客户端程序运行在客户机上自动将指定目录下的文件备份到服务器并且能够支持浏览器查看与下载其中下载支持断点续传功能并且服务器端对备份的文件进行热点管理将长时间无访问文件进行压缩存储。
开发环境centos7.6/vim、g、gdb、makefile以及windows11/vs2022
技术特点http客户端/服务器搭建json序列化文件压缩热点管理断点续传线程池读写锁单例模式
项目模块
服务端 数据管理模块内存中使用hash表存储提高访问效率持久化使用文件存储管理备份数据业务处理模块搭建http服务器与客户端进行通信处理客户端的上传下载查看请求并支持断点续传热点管理模块对备份的文件进行热点管理将长时间无访问文件进行压缩存储节省磁盘空间。 客户端 数据管理模块内存中使用hash表存储提高访问效率持久化使用文件存储管理备份数据文件检索模块基于c17文件系统库遍历获取指定文件夹下所有文件。文件备份模块搭建http客户端上传备份文件。