该项目利用FastDFS分布式文件系统以及集群等技术提供统一的接口对外提供文件存储和访问服务,使用户能够通过网络访问服务端的文件资源,满足海量数据存储的需求
项目采用B/S模型,服务端与浏览器进行交互,将用户的操作转换为HTTP请求发送给服务端,在服务端使用Nginx作为反向代理服务器进行请求转发,由FastCGI进程处理对应的请求,FastDFS实现文件的分布式存储。同时使用MySQL作为项目数据信息的存储,Redis作为缓存存储session与热点数据。
字段名 | 字段类型 | 约束 | 字段说明 |
---|---|---|---|
id | bigint | PRIMARY KEY、AUTO_INCREMENT | 文件序号 |
md5 | varchar(256) | NOT NULL | 文件md5 |
file_id | varchar(256) | NOT NULL | 文件id,对应FastDFS的文件路径 |
url | varchar(512) | NOT NULL | 文件的完整存储路径:192.168.52.139:80/group1/M00/00/00/xxx.png |
size | bigint | 文件大小(字节) | |
type | varchar(32) | 文件类型(png\zip…) | |
count | int | 文件引用计数 |
字段名 | 字段类型 | 约束 | 字段说明 |
---|---|---|---|
id | int | PRIMARY KEY、AUTO_INCREMENT | 主键 |
user | varchar(32) | NOT NULL | 文件所属用户 |
md5 | varchar(256) | NOT NULL | 文件md5 |
file_name | varchar(128) | 文件名 | |
pv | int | DEFUALT 1 | 文件下载量 |
create_time | timestamp | 文件共享时间 |
字段名 | 字段类型 | 约束 | 字段说明 |
---|---|---|---|
id | int | PRIMARY KEY、AUTO_INCREMENT | |
user | varchar(128) | NOT NULL、UNIQUE | 文件所属用户、共享的文件 |
count | int | 拥有的文件数量 |
字段名 | 字段类型 | 约束 | 字段说明 |
---|---|---|---|
id | int | PRIMARY KEY、AUTO_INCREMENT | |
user | varchar(32) | NOT NULL | 文件所属用户 |
md5 | varchar(256) | NOT NULL | 文件md5 |
create_time | timestamp | 文件创建时间 | |
file_name | varchar(128) | 文件名 | |
shared_status | int | 共享状态 | |
pv | int | 文件下载量 |
字段名 | 字段类型 | 字段约束 | 字段说明 |
---|---|---|---|
id | int | PRIMARY KEY、AUTO_INCREMENT | 用户id |
user_name | varchar(32) | UNIQUE、NOT NULL | 用户名称 |
nick_name | varchar(32) | UNIQUE、NOT NULL | 用户昵称 |
password | varchar(32) | NOT NULL | 密码 |
phone | varchar(16) | NOT NULL | 手机号码 |
varchar(64) | 邮箱 | ||
create_time | timestamp | 时间 |
项目使用FastCGI进程处理对应的请求,FastCGI会一直阻塞等待客户端连接,当有客户端连接到来的时候就获取连接以及判断数据包是否合法,如果合法就解析数据进行业务处理,否则输出错误。
//阻塞等待用户连接
while (FCGI_Accept() >= 0) {
// 获取数据包内容长度
char *contentLength = getenv("CONTENT_LENGTH");
int len;
printf("Content-type: text/html\r\n\r\n");
if( contentLength == NULL ) {
len = 0;
} else {
len = atoi(contentLength); //字符串转整型
}
// 没有请求相关信息
if (len <= 0) {
printf("No data from standard input.\n");
LOG(REG_LOG_MODULE, REG_LOG_PROC, "len = 0, No data from standard input\n");
} else {
// 解析数据包进行业务处理
}
业务逻辑
业务逻辑
token
相当于令牌,是服务端生成的一个字符串,用于验证客户端的身份,不需要在服务端存储用户的登录记录
流程:
生成规则:生成4个随机数并对随机数进行加密,再将加密后的随机数进行base64编码,最后转换为定长的MD5
服务端将token保存在Redis中同时设置有效期(24小时),key为用户名,value为token
base64
使用64个字符表示任意二进制数据的方法,防止不可见的编码
二进制文件中可能存在很多无法显示和打印的字符,这些字符在网络中传输的过程中经过的不同设备处理方式可能不同,导致不可见的字符可能被错误处理
需要先对数据进行编码转换为可见的字符(比如ASCII码)保证数据的可靠传输
Base64将每三个8bit的字节转换为四个6bit的字节,再在6bit添两位高位0组成四个8bit的字节,转换后的字符串比原来要长1/3
每个文件都有一个唯一的MD5值用于唯一的标识文件
客户端在上传文件之前将文件的MD5上传到服务器上,服务器判断是否已经存在MD5:如果存在说明文件已经存在无需再上传;如果不存在才真正上传文件
业务逻辑
对于用户来说MD5+文件名一样才是重复的文件,但是对于FastDFS来说MD5一样就是重复的文件
业务逻辑
upload_to_dstorage将文件上传到FastDFS中
采用多进程方式,通过匿名管道在父子进程之间传输数据。由子进程读取本地临时文件中的内容上传到FastDFS中,获取到file_id写入管道中,父进程读取管道中的内容并回收子进程的资源
为什么采用多进程方式:防止上传文件过程中发生错误导致进程崩溃进而导致整个上传文件系统崩溃;采用多进程方式子进程在上传文件过程中崩溃了父进程还可以获取子进程崩溃信息等,不会影响到父进程,避免系统不可用
获取文件所存放storaged的host_name并拼接处完整的HTTP地址
采用多进程方式,通过匿名管道在父子进程之间传输数据
子进程利用fdfs_file_info进程读取文件的详细存储信息,获取storage的host_name并写入管道中
父进程读取管道中的信息拼接出完整的HTTP地址
业务逻辑
获取共享文件个数
获取共享文件列表
获取共享文件排行榜
业务逻辑
业务逻辑
业务逻辑
业务逻辑
业务逻辑
业务逻辑