基于云存储的图像管理平台设计与实现

img

毕 业 设 计

img

题目: 基于云存储的图像管理平台设计与实现

学 生: 王骏

学 号: 201606060129

学 院:电子信息与人工智能学院

专 业: 计算机科学与技术

指导教师: 齐勇

2020 6 30

img

毕业设计(论文)任务书

电子信息与人工智能 学院 计算机科学与技术 专业 163班级 学生:王骏

题目: 基于云存储的图像管理平台设计与实现

毕业设计(论文)从 2020 2 24 日起到 2020 6 15

课题的意义及培养目标:

在本本次毕业设计中,将会综合运用本科所学计算机科学与技术专业相关知识,完成实际的应用开发。

传统的云存储系统采用集中的存储服务器存放所有数据,存储服务器成为系统性能的瓶颈,也是可靠性和安全性的焦点,不能满足大规模存储应用的需要。

分布式网络存储系统采用可扩展的系统结构,利用多台存储服务器分担存储负荷,利用位置服务器定位存储信息,它不但提高了系统的可靠性、可用性和存取效率,还易于扩展。因此,本项目利用多台服务器的存储资源来弥补传统云存储系统的不足,通过Nginx服务器作为负载均衡服务实现高负载的分布式云存储方案。

设计(论文)所需收集的原始数据与资料:

C++相关的开发软件工具,Qt客户端设计工具,Nginx服务器,Linux操作系统,MySQL数据库,Redis数据库,分布式文件系统,项目所需的图像数据,分布式文件系统相关资料。

课题的主要任务(需附有技术指标分析):

本次设计主要为高负载高并发基于分布式的图像管理存储平台。主要实现用户注册,用户登陆,图像文件列表获取,文件上传,下载,分享,删除等基本功能。

本次设计采用C/S架构,分为客户端和服务端,客户端采用Qt进行界面设计。服务端的基本流程为,客户端请求经过反向代理后通过HTTP服务器请求进行相应分布式文件系统管理及数据库管理。以上传为例,首先客户端的请求通过Nginx反向迭代处理作为负载均衡方案,之后通过对应服务器请求先进行数据库信息校验,当该上传数据不存在时,通过追踪器将图像数据存储到相应的分布式文件系统中,再将存储信息存储至数据库以及缓存数据库中。

预计:并发量同步请求初步预计500人左右。本地测试上传速度:30MB/S ~ 50MB/S 客户端下载速度: 20MB/S ~ 40MB/S 服务器中上传速度: 5MB/S ~ 7MB/S 客户端下载速度: 0.1MB/S~ 0.15MB/S

设计(论文)进度安排及完成的相关任务(以教学周为单位):

周 次 设计(论文)任务及要求
1-3 相关资料的查阅与学习
4-5 整个方案的初步设计
6-10 代码的设计与实现
11-12 测试与bug修复
13-14 论文的梳理
15-16 论文的完善

​ 学生签名:

​ 指导教师:

​ 教研室主任:

基于云存储的图像管理平台设计与实现

摘 要

随着计算机与网络的发展,国内外的图像存储已逐渐实现由传统图像向数字化图像转型。这意味着图像越来越多地以二进制信息保存在计算机中,这样不仅可以长期保存,而且还有方便复制、随意修改、便于传输等优点。而随着大数据与云计算的发展,图像的存储逐渐也向分布式存储方向发展,使得图像管理的物理存储资源不一定直接连接在本地节点上,而是通过计算机网络与节点相连。分布式文件系统的设计基于C/S模式。而且分布式文件系统也轻松解决了海量图像处理的难题。

利用大数据和云计算的优势,以云存储的方式进行图像数字化存储管理,可以解决常规对象存储所常见的海量图像存储效率低下且不安全、服务器无法承载多用户并发访问等问题。因此设计一套基于分布式文件系统的云存储图像管理平台,为用户提供高效且安全的图像上传、下载、分享、预览等对象存储与管理服务,解决常规物理存储所带来的数据易丢失难恢复、下载存储不方便、存储空间有限、需随身携带等问题,同时解决普通存储网盘用户并发量低下、数据共享性差等问题。

平台采用C/S模型,即客户端/服务端模式。客户端通过Qt可视化设计工具设计用户界面与文件管理界面,客户端语言通过使用Qt类库完成客户端逻辑。服务端框架首先采用Nginx服务器进行反向代理,解决负载均衡与高并发问题;数据对象存储通过分布式文件系统FastDFS进行数据存储;数据库通过持久化数据库MySQL与缓存数据库Redis的协调工作进行数据信息管理;服务端语言采用以C++语言为主的CGI程序完成服务端逻辑。

基于云存储的图像管理平台,最终为用户提供高效且安全的图像云存储与管理服务,包括用户的登录与注册、数据上传、数据下载、文件列表浏览、共享文件浏览、下载榜浏览、数据传输情况浏览、文件的共享与转存、数据删除、图像预览等功能,可作为图床进行图像存储,也可作为云盘进行对象存储,方便用户对图像数据进行数字化管理。

关键词:云存储,分布式文件系统,Nginx,MySQL,C++,Qt

Design and I**mplementation of I**mage M**anagement P**latform based on C**loud S**torage

ABSTRACT

With the development of computer and network, image storage at home and abroad has gradually realized the transformation from traditional image to digital image. This means that the image is more and more stored in the computer with binary information, which not only can be saved for a long time, but also has the advantages of convenient replication, arbitrary modification, easy transmission and so on. With the development of big data and cloud computing, the storage of images is also gradually developing towards distributed storage. The design of distributed file system is based on C / S mode. Moreover, the distributed file system can easily solve the problem of massive image processing.

By using the advantages of big data and cloud computing, digital image storage management in the way of cloud storage can solve the common problems of mass image storage, such as low efficiency and insecurity, the server can not carry multi-user concurrent access and so on. Therefore, a set of cloud storage image management platform based on the distributed file system is designed to provide users with efficient and safe image upload, download, share, preview and other object storage and management services, to solve the problems brought by the conventional physical storage, such as easy loss and hard recovery of data, inconvenient Download and storage, limited storage space, need to carry around, and to solve the common storage network disk There are many problems such as low concurrent users and poor data sharing.

The platform adopts C / S model, namely client / server mode. The client uses QT visual design tool to design user interface and file management interface, and the client language uses QT class library to complete the client logic. The server framework first uses nginx server as the reverse proxy to solve the problem of load balance and high concurrency; the data object storage uses fastdfs as the distributed file system for data storage; the database uses MySQL as the persistent database to coordinate with redis as the cache database for data information management; the server language uses CGI program based on C + + to complete the server logic.

The image management platform based on cloud storage provides users with efficient and safe image cloud storage and management services, including user login and registration, data upload, data download, file list browsing, shared file browsing, download list browsing, data transmission browsing, file sharing and transfer, data deletion, image preview and other functions, which can be used as a drawing bed Image storage can also be used as cloud disk for object storage, which is convenient for users to digitize image data management.

Key words: Cloud Storage, Distributed File System, Nginx, MySQL, C + +, QT

目 录

摘 要 I

ABSTRACT II

1 绪论 1

1.1 课题背景 1

1.2 发展趋势 1

1.3 项目意义 2

2 需求分析 4

2.1 功能需求分析 4

2.1.1 服务端功能需求分析 4

2.1.2 客户端功能需求分析 4

2.2 可行性分析 5

2.2.1 经济可行性分析 5

2.2.2 技术可行性分析 5

2.2.3 运行可行性分析 5

2.2.4 操作可行性分析 6

3 技术支持 7

3.1 FastDFS分布式文件系统 7

3.2 Nginx服务器反向代理与负载均衡 8

3.3 Qt客户端GUI界面设计 10

4 设计方案 12

4.1 设计原理 12

4.2 总体设计方案 12

4.2.1 客户端设计方案 13

4.2.2 服务端设计方案 14

4.3 功能模块方案 14

4.3.1 用户注册与登录 14

4.3.2 文件列表查询 16

4.3.3 数据上传与秒传 16

4.3.4 文件删除 18

4.3.5 文件共享与共享列表查询 19

4.3.6 数据下载 20

4.3.7 图像预览 21

4.4 流程关系 22

4.4.1 客户端流程 22

4.4.2 服务端流程 23

5 具体实现 25

5.1 服务端架构实现 25

5.1.1 负载均衡 25

5.1.2 数据库设计 25

5.1.3 文件对象存储 28

5.2 客户端架构实现 29

5.2.1 用户界面设计 29

5.2.2 文件界面设计 31

5.2.3 基础功能模块 35

5.3 功能模块实现 38

5.3.1 数据封装与提取 38

5.3.2 用户登录与注册 39

5.3.3 数据上传模块(上传、秒传) 40

5.3.4 文件查询模块(文件列表、共享列表、下载榜) 41

5.3.5 文件处理模块(删除、共享、转存) 42

5.3.6 数据下载模块 43

5.3.7 图像预览模块 43

6 测试 46

6.1 程序调试 46

6.2 工具测试 46

6.2.1 测试的目的和意义 46

6.2.2 测试框架 46

6.2.3 测试步骤 46

6.3 测试用例设计 47

6.4 测试数据及结果 48

6.4.1 功能测试数据及结果 48

6.4.2 性能测试结果 52

7 总结 53

致 谢 54

参 考 文 献 55

附 录 57

1 绪论

1.1 课题背景

由于大数据与云计算技术的普及,互联网已经与人们的生活越来越密切,人们无时无刻不产生着各种数据。同时伴随着直播、短视频、电子相册、数字影院等流媒体的发展,图像数据处理需求正急速增长,传统的物理存储由于共享性差、数据处理缓慢、不易于迁移与恢复等缺点,已渐渐不适用于业务发展需求。而随着云计算的发展,分布式存储的大容量存储、方便移植、快速存储、快速共享、快速备份等各种优点逐渐显现出来,图像存储已渐渐从传统的物理存储方式转变为云存储方式。

基于云存储的图像管理方式是大数据时代数据对象存储的重要方式之一,这种对象存储方式不仅应用于图像管理,更应用于大数据时代影视、文件、用户信息等各种数据存储之上。通过云存储的方式,可对数据随时上传下载,随时分享备份,使数据对象的管理更加方便方便,更加安全。项目尝试采用分布式文件系统对数据对象进行存储,同时采用Nginx服务器实现高并发与负载均衡,对海量用户的请求进行响应,为用户提供可靠、方便的图像管理平台。

1.2 发展趋势

随着计算机与网络的发展,国内外的图像存储已逐渐实现由传统图像向数字化图像转型。这意味着图像越来越多地以二进制信息保存在计算机中,这样不仅可以长期保存,而且还有方便复制、随意修改、便于传输等优点。而随着大数据与云计算的发展,图像的存储方式逐渐向分布式存储方向发展,使得图像管理的物理存储资源不一定直接连接在本地服务器结点上,而是通过网络与存储结点连接[1],因此衍生出了分布式文件系统。分布式文件系统即集群文件系统,是指物理存储资源通过网络与结点相连,支持大数量的节点以及PB级的数量存储[2]。因此,分布式文件系统解决了海量图像处理相关的难题。

国内自从2008到2009年间,以华为为代表的一些国内互联网企业开始踏足个人云存储业务,开发出国内第一批网盘产品。2010年以后,出于占领大数据时代入口的目的,国内互联网巨头也纷纷布局云存储业务,腾讯、百度、360、金山、华为等互联网企业也陆续推出了自己的云盘,并开始跑马圈地[3]。这意味着大数据不仅为国内开拓了广阔的市场,也使得国内已逐渐由传统存储向云存储转型[4]。而自从阿里云、腾讯云纷纷崛起,不仅推动了云计算在国内的发展,也在客观上对国内的市场进行了开拓,对云服务提供商们形成了刺激作用。2018年我国数字经济规模达到31.3万亿元,占当年GDP比重达34.8%[5]。

进入5G时代,5G将与AI智能、IoT物联网、Cloud云、Big Data大数据、Edge Cloud边缘云等技术交叉发展,共同构建智能化的基础设施。云已成为新型信息基础设施的重要组成部分,也是面向政企提供数字化服务的主入口,各行各业的数字化发展已经离不开云计算的支撑。中国云市场IaaS、PaaS、SaaS服务模式继续协同发展,市场规模随客户需求的变化而调整[6]。

国外云存储市场2017年为307亿美元,预计到2022年889.1亿美元,CAGR为23.7%[7]。中国云存储市场2017年规模为88.68亿人民币,同比增长71.8%,2018年同比增长率将上升至72.8%[8],市场规模为158.5亿元人民币。Gartner在2019年的报告中显示:到2024年,40%的企业将实施至少一种混合云存储方式,高于2019年的10%[9]。存储如何更好的服务私有云,成为企业级存储的一个重要课题。除了存储自身的池化、自动化之外,向上提供API,方便私有云管理平台按需驱动存储资源的创建、调整、优化甚至回收,将逐渐成为必备配置。云化对接包含两大块,一是对接开源的云管理平台;二是对接商业的云管理平台,首当其冲的是能够被主流Hypervisor识别,如VMware ESXi、Microsoft Hyper-V[10]。

1.3 项目意义

如今数据处理需求飞速增长,稍不留神便会跟不上时代发展的步伐。传统的数据管理技术已逐渐不能满足互联网应用所提出的对大数据管理的要求。如何高效地存储和管理海量图像数据,已然成为当今时代的热门探讨话题。

而云存储、云服务、虚拟化等IT热词的不断盛行,已标志着云计算正引领着时代发展的趋势。相较于传统的物理存储,基于云存储的图像管理方式不仅解决了物理硬件易损坏、数据易丢失的问题,而且存储容量可弹性扩展,这意味着基于云存储的图像管理方式不仅扩容方便,而且在存储更新或者服务升级的过程中并不会引起服务中断,造成不必要的损失。

本着开源精神,借鉴传统数据存储与管理的方式,针对大数据与云计算的特点,设计了一套基于云存储的图像管理平台,方便管理图像数据。该平台采用分布式文件系统、缓存数据库、负载均衡等技术,具备弹性伸缩、弹性扩容、高并发等特点,支持海量图像数据的存储与管理。实践证明,该平台具备可行性,可满足空间信息服务的多种需求。

平台设计使用的服务器是基于FastDFS分布式文件系统以及Nginx服务器作为反向代理的Linux服务器,编程语言使用C++语言,图像存储于FastDFS中,数据信息存储于持久性数据库MySQL,Redis作为辅助提高访问效率。客户端使用Qt作为开发工具设计该平台。该平台客户端界面美观方便,功能齐全。数据采用Md5加密算法与Base64数据处理技术,保证数据传输的安全性[11]。该平台是一个简单实用的图像管理平台,具有以下功能:

用户注册与登录,文件的上传与下载,查询与删除,共享与转存。同时针对图像文件具备预览功能。

该平台重在为用户提供一套完整的图像管理与存储服务,解决常规物理存储所带来的数据易丢失难恢复、下载存储不方便、存储空间有限、需随身携带等问题,同时解决普通存储网盘用户并发量低下、数据共享性差等问题。

2 需求分析

2.1 功能需求分析

2.1.1 服务端功能需求分析

传统的云存储方式将数据直接集中存储于某一台或多台服务器或者硬盘上,这样虽然方便服务端的查询,但是一旦服务器或硬盘损坏,便会造成数据丢失且无法恢复。而且由于数据无法直接共享,导致资源的浪费。如今随着时代的发展,无论软件还是硬件的更新速度越来越快,传统的存储方式由于更新麻烦,数据迁移或备份困难,因此已渐渐被分布式存储所替代。因此,对于服务端,应该满足以下需求:

(1) 功能需求

(a) 为用户提供云存储服务。

(b) 满足用户完备的图像管理功能需求。

(c) 对于用户的数据管理应具备快速响应。

(d) 针对多人访问服务器的情况应具备负载均衡的能力。

(e) 数据应具备快速备份与易迁移的特性,保证用户数据不会因服务器问题而丢失。

(2) 性能需求

(a) 多人同时访问服务器应具备高并发性。

(b) 并发不会带来内存泄露等安全问题。

(c) 对于高频数据访问应快速响应,而低频数据应不过多占用内存资源。

(d) 对于用户的信息例如密码等敏感信息应保证安全性。

(e) 程序执行流程合理,代码思路清晰,不会造成逻辑上的问题。

(3) 可靠、可用性需求

(a) 针对各类错误应有相应的提示或解决方案。

(b) 对于失败操作需要有一套完整的错误码进行失败原因提示与排查。

2.1.2 客户端功能需求分析

客户端作为用户一系列操作的载体,对用户的使用体验起着最直接的决定作用。因此,客户端不仅需要具备齐全的功能服务,还需具备美观、操作简单、处理流畅等特性,这样才能避免用户的流失。因此,将客户端独立出来进行需求分析。以下从业务需求与性能需求两部分进行分析:

(1) 业务需求

(a) 为用户提供用户身份的载体,因此需包含用户登录与注册界面。

(b) 作为平台的核心,需具备上传图像与下载图像的功能按钮。

(c) 方便数据的交互,因此需具备共享文件的浏览界面。

(d) 提高用户数据获取的速度,为用户提供数据下载量的界面。

(e) 为节约用户空间,需为用户提供图像预览的功能。

(f) 为节约加载速度,可增加缓存机制。

(2) 性能需求

(a) 界面简约又不失美观。

(b) 任何操作不造成客户端界面交互无响应。

(c) 在数据交互的过程中需保证数据的安全性。

(d) 及时对服务端响应异常的情况进行处理。

2.2 可行性分析

2.2.1 经济可行性分析

对于该平台软件所需要的一系列相关资料均可以通过互联网和文献材料进行获取采集,由于开源软件的盛行,对于软件所依赖的各种库均可从GitHub网站获取。而国内云计算的发展,无论操作系统还是硬件设备均可从国内云计算公司获取,无需特殊的工具,且开发成本较低,软件程序简单易实现,从经济的角度来看,对于该平台软件的开发经济方面可行。

2.2.2 技术可行性分析

由于开源软件的盛行,目前主流的分布式文件系统均具备备份与数据迁移功能,同时也能保证数据的安全性。而针对高并发问题,目前Nginx服务器可通过反向代理实现负载均衡,解决了高并发的问题[12]。而随着非关系型数据库的发展,针对高频访问的数据可直接存入非关系型数据库中,这样便显著提高了访问效率。对于客户端与服务端数据如何进行交互,这已经在互联网正式普及之时便已解决,而作为主流可靠的传输方式,HTTP协议已经成为TCP传输的典范。因此,从技术角度来看,通过HTTP协议将客户端数据传输服务端,服务端通过Nginx服务器进行反向代理,监听网络,通过CGI程序将接收到的数据加以处理,数据存储于FastDFS中,信息存储于MySQL,同时Redis加以辅助[13],这种设计方式是可行的。

2.2.3 运行可行性分析

运行性是对组织结构最直观的影响,它决定着用户的体验感。主要体现在客户端美观与流畅上。而该平台的设计界面通过Qt设计,简约而不失美观,操作十分简单,功能齐全,由于Qt各种动态库获取方便,因此只需要有相应的动态库文件,在Windows操作系统上安装便可运行。

2.2.4 操作可行性分析

软件的设计开发分为客户端与服务端两部分,客户端主要所采用的工具是Qt 5.4.1,开发出的应用程序客户端在Windows操作系统的计算机上运行,分为用户界面与文件界面两部分,以UI界面窗口的方式呈现给用户,接收鼠标和键盘的输入,以显示器作为载体输出,符合新时代计算机操作系统用户的使用习惯,方便用户对图像数据进行存储和管理,包括用户的登录、注册以及图像的上传、下载、共享、预览、转存、秒传、删除等一系列操作,简单而且容易上手。而服务端作为用户数据的载体,必须保证数据的安全性与可靠性,因此服务端的操作均由服务端代码进行处理,不直接授予用户权限。所以此软件在操作上是可行的。

综上所述,该平台软件的开发与设计从经济、技术、运行、操作等各个方面完全可行。

3 技术支持

3.1 FastDFS分布式文件系统

传统的网络存储系统通过集中的存储方式将全部数据存放到服务器上[14],因此服务器的性能成为数据安全性与可靠性的关键。而针对以数据为根本的大数据时代,显然传统的网络存储方式已不能满足时代的要求。因此,衍生出了分布式文件系统。

分布式文件系统可以简单理解为将对象数据离散地分布存储到许多台独立的存储设备上。分布式文件系统存储方式采用弹性扩展的结构,通过多态弹性服务器来分担数据存储的负荷,通过追踪器服务器来定位存储的结点,这种方式不仅提高了系统的执行效率,而且由于其本身易于扩展的特性,显著提高了系统的实用性与可靠性。

FastDFS分布式文件系统是一款轻量级开源项目,由C语言实现,支持Uinx、Linux等操作系统,为互联网应用开发定制。可用于管理不局限于图像的各种数据,包括对象存储、数据同步、上传、下载、删除等一系列操作[15],解决了大空间存储和负载均衡等问题,追求高性能和弹性扩展。

FastDFS分布式文件系统分为三部分:追踪器Tracker,存储结点Storage,客户端Client。客户端Client和存储结点Storage请求连接追踪器Tracker,Storage主动向Tracker报告空闲存储空间、数据同步状况、上传下载次数等信息。每次启动时存储结点会启动单线程实现对追踪器的连接与汇报信息。FastDFS可划分多个组,每组所包含的存储结点由追踪器获取。整体架构如下图:

img

图3-1 FastDFS分布式文件系统结构

FastDFS集群可分为追踪器集群与存储结点集群,追踪器集群之间是平等的关系,不存在单点故障的情况,Client访问追踪器通过轮回的方式请求。存储结点集群通过分组的方式集群,存储容量为每个存储结点容量之和[16]。

FastDFS集群的扩容分为横向扩容与纵向扩容,横向扩容可通过添加组的方式进行空间扩充,而纵向扩容用来实现备份,一组内的最大容量为当前组内存储结点中空间最小的服务器容量。集群整体结构如下:

img

图3-2 FastDFS分布式文件系统集群

3.2 Nginx服务器反向代理与负载均衡

Nginx是一款轻量级的Web 服务器/反向代理服务器及电子邮件代理服务器,采用C进行编写。不仅可以作为HTTP服务器相应Web请求,同时还可以作为反向代理服务器。其特点是占有内存少,并发能力强。Nginx 既可以直接支持Rails和PHP程序,也可以支持作为HTTP代理服务对外服务[17]。

img

图3-3 反向代理服务器原理

Nginx三个核心功能是静态服务器、反向代理和负载均衡[18]。这三个功能通过配置文件来实现,所有配置选项代码大致分为以下几部分:

main # 全局配置

events { # Nginx工作模式配置

}

HTTP { # HTTP设置

​ ….

​ server { # 服务器主机配置

​ ….

​ location { # 路由配置

​ ….

​ }

​ location path {

​ ….

​ }

​ location otherpath {

​ ….

​ }

​ }

​ server {

​ ….

​ location {

​ ….

​ }

​ }

​ upstream name { # 负载均衡配置

​ ….

​ }

}

如上述配置文件所示,主要由6个部分组成:

(a) main:用于全局信息的配置。

(b) events:用于Nginx工作模式的配置。

(c) HTTP:用于进行HTTP协议信息的一些配置。

(d) server:用于进行服务器访问信息的配置。

(e) location:用于进行访问路由的配置。

(f) upstream:用于进行负载均衡的配置。

upstream模块主要负责负载均衡的配置[19]。简单的配置方式如下:

upstream name {

​ ip_hash;

​ server 192.168.1.100:8000;

​ server 192.168.1.100:8001 down;

​ server 192.168.1.100:8002 max_fails=3;

​ server 192.168.1.100:8003 fail_timeout=20s;

​ server 192.168.1.100:8004 max_fails=3 fail_timeout=20s;

}

核心配置信息如下:

(a) ip_hash:指定请求调度算法。

(b) server host:port:分发服务器的列表配置。

(c) down:表示该主机暂停服务。

(d) max_fails:表示失败最大次数,超过失败最大次数暂停服务。

(e) fail_timeout:表示请求失败,指定的时间后重新请求。

3.3 Qt客户端GUI界面设计

Qt作为一款开源的跨平台图形界面开发框架,既可以对GUI进行设计,同时由于其是基于C++的面向对象的框架,因此同样可以作为C++编译软件编写程序。Qt类库中的类大致分为两种类型:一种是独立的不从任何类集成的类;另一种直接继承自Qt类。

独立的类通常在Qt类库中用来实现独立的功能。继承自Qt的类主要分为QEvent类和QObject类。QEvent类是所有QT事件响应类的基类,QObject类是所有应用组件的基类[20]。

QWidget类是组件容器,所有能结合在一起的组件均继承自从该类。而QWidget类则继承自QObject基类[21]。

信号和槽是Qt引进的一种处理机制,信号可以被理解为一个对象发出的事件请求,槽是处理信号的函数。

信号和槽能完成回调函数的所有功能,并且信号和槽机制是类型安全的,而且还能完成其他许多复杂的功能。

信号和槽可以是单一或者多对多的关系。一个信号可以被连接到多个槽,一个槽也可以响应多个信号,此外,信号之间也可以被连接[22]。

4 设计方案

4.1 设计原理

该项目的设计采用C/S结构,即客户端/服务端模式。首先,客户端响应用户的请求,将用户的请求封装成Json格式,然后通过HTTP协议发送给服务端。对于密码等敏感信息可通过Md5加密后封装成Json格式发送[23]。在整个数据交互的过程中,客户端始终保证用户操作的合理性。

服务端通过指定端口接收到数据后,首先由Nginx服务器进行反向代理,将数据转发给Nginx配置文件中记录的Web服务器IP。Web服务器接收到数据后根据当前数据HTTP请求头的类型将不同类型数据,通过配置文件中对应的端口转发给服务器相应的CGI程序进行处理,端口对应的CGI程序首先对数据进行拆解,获取数据具体的请求,然后进行处理,并将处理结果转发给客户端。

对于数据对象本身,CGI程序通过分布式文件系统追踪器对存储结点的数据进行操作,对于信息类数据,CGI程序则将对持久性数据库MySQL进行一系列操作,同时缓存数据库Redis加以辅助提高效率。

整体结构如下:

img

图4-1 总体设计框架

4.2 总体设计方案

该平台总体包括客户端与服务端两部分。二者之间数据以Json格式通过HTTP协议进行交互。同时对于特殊数据例如密码需进行Md5加密,然后封装Json格式传输。

客户端主要分为界面设计与功能模块两部分。界面设计分为用户界面和文件界面,其中用户界面包括登录界面、注册界面、设置界面;文件界面包括我的文件、共享文件、下载榜、传输列表。功能模块包括基础功能模块与特殊功能模块,其中基础功能统一封装在一个基础功能类中,用于实现包括数据封装与解析、HTTP传输、读取配置文件、加密等功能;特殊功能模块作为工具类,包括实现上传下载任务与进度、图像预览等功能。

服务端主要包括服务端框架搭建与功能模块两部分。服务端框架包括Nginx与负载均衡、MySQL数据库与Redis缓存数据库、分布式文件系统的搭建。功能模块用于实现包括用户注册与登录、文件上传与秒传、文件列表查询、文件共享与转存、文件删除、文件下载等功能[24]。

具体整体设计方案如下图:

img

图4-2 总体方案结构

4.2.1 客户端设计方案

由于客户端是用户直接进行数据交互的载体,因此客户端在达到美观简洁的同时需要有平台完整的功能。根据平台的需求,客户端采用Qt编译器进行客户端代码的编写与界面的设计。作为图像文件管理平台,需要为用户提供文件界面供用户进行管理操作;同时为方便用户信息的验证,客户端还需用户界面获取用户的信息。因此客户端包括用户界面与文件界面。

用户界面通过一个主QWidget,包含三个子QWidget,分别作为登录、注册、设置三个子界面,通过不同的按钮切换不同的子界面。登录注册用于用户的身份校验,设置用于设置代理服务器服务器的端口号和IP用于数据交互。

通过登录界面信息校验成功后会关闭用户界面,同时打开文件界面。文件界面包括头部和信息部两部分组成,头部包含多个文件功能切换按钮,信息部界面主要用于对文件信息的展示,因此在设计上,头部作为公共部分只需一个QWidget派生类,而信息部分展示界面通过不同的QWidget派生类与头部拼接成不同的文件界面。

4.2.2 服务端设计方案

对于服务端,需要保障数据的高并发与流畅性,因此通过一个Nginx服务器配置使得客户端直接连接的服务器具备反向代理与负载均衡的功能。由于Nginx服务器不能直接处理动态数据,因此Web服务器需要借助CGI程序来处理动态响应。处理不同事件的CGI程序绑定Web服务器不同的端口,通过HTTP协议请求头来确定对应端口,供CGI程序处理。对于数据本身,CGI程序通过分布式文件系统提供的API对分布式文件系统进行操作。同时对于信息类数据存于MySQL,将访问量大的数据插入非关系型数据库,以便下次查找直接从非关系型数据库中提取数据。

对于分布式文件系统采用FastDFS,需要配置追踪器与存储节点,使得服务器构建成一个集群。同时对于每一台存储节点服务器,通过Storage与Nginx绑定,使得存储于存储节点服务器的数据可通过Url的方式直接访问,而不需重新下载。这样只需将文件对应的Url存储于数据库中,下载或者访问时直接通过访问数据库中的Url即可,不需再从存储节点中下载后发送给客户端,显著地提高了下载与访问效率。

对于数据库采用MySQL进行数据库设计以及增删改查,根据需求需建五张表,用户表用于用户登录的确认,文件表作为文件信息的保存,共享文件表用于共享文件信息的获取,用户文件表用于用户文件信息的获取,用户文件数量表用于辅助用户访问文件界面时文件的展示,同时为扩展功能提供预留空位。

缓存数据库通过Redis对访问频繁的数据进行存储。每次获取信息先查询Redis,如果没有需要的信息则访问MySQL,同时将查询数据存入Redis,提高数据获取效率。

4.3 功能模块方案

4.3.1 用户注册与登录

对于用户模块可按功能具体划分为注册模块与登录模块。二者客户端为通过继承用户界面而派生的两个子界面。服务端主要对数据库进行操作。

注册的客户端逻辑为:用户通过进入注册界面的填写注册信息,客户端代码获取数据后进行逻辑判断,如果用户名或昵称不符合格式要求,则向客户端反馈用户名或昵称格式不符合要求的消息;如果密码不符合格式要求或两次输入密码不一致,则向客户端反馈密码相关操作失败的消息;如果电话或者邮箱不符合规范,则向客户端反馈电话或者邮箱格式不规范的消息。如果用户填写的注册信息均通过客户端校验格式的代码验证,则首先用Md5对密码加密,然后封装成Json格式以HTTP协议发送给服务端。如果服务端长时间未响应则反馈注册失败信息。Web服务端通过请求头为reg交给相应端口的CGI程序。服务端CGI程序的逻辑为:首先将Json数据提取出来,然后查询数据库用户表与通过Json解析的用户名进行比对,如果用户表存在该用户名,则反馈用户名重复的状态码,否则将该注册用户信息插入用户表中,反馈注册成功的状态码。客户端接收到状态码后,通过比对,如果不为成功状态码则根据状态码类型向用户反馈注册失败的原因,并提示用户重新注册;否则客户端会提示用户注册成功,同时会跳转至用户登录的界面,待用户进行登录操作。

注册流程如下:

img

图4-3 用户注册流程图

登录的客户端逻辑为用户通过登录界面填写用户名与密码,如果选择记住密码则登录成功后会把用户以及用户密码的Md5值保存到缓存配置文件中[25]。用户通过登录界面填写登录信息,点击登录按钮,客户端会通过信号槽将登录信息向服务端发送,Web服务端根据请求头为login交给相应端口的CGI程序。服务端CGI程序的逻辑为首先将Json数据提取出来,然后查询数据库用户表与解析后的用户名与密码进行比对,如果存在该用户名,并且密码Md5值跟数据库中密码存储信息一致则反馈注册成功状态码,否则反馈根据情况反馈登录失败状态码。客户端接收到状态码后,如果不为登录成功状态码则提示用户登录失败,否则客户端跳转至我的文件界面。

登录流程如下:

img

图4-4 用户登录流程图

4.3.2 文件列表查询

当用户进入文件界面后,客户端需要保存当前用户的所有文件信息,因此会向服务端发起当前用户的文件查询请求。当服务端通过请求头myfile将用户信息交给相应端口的CGI程序。CGI程序逻辑为通过以用户名查询数据库user_file_list表将所有文件信息传给客户端,客户端获取到所有信息后,通过QWigitList将文件信息按图标的形式排列到界面,同时在排列过程中对于文件为图像类型的文件进行判断,如果该图像文件在缓存中有缩略图,则显示缩略图,否则显示默认图片。

img

图4-5 文件列表查询流程图

4.3.3 数据上传与秒传

当用户进行上传操作时,首先是采取秒传的方式,将待上传文件的信息通过Md5加密,然后封装好数据后通过HTTP传输,服务端通过Md5请求头交给负责秒传的CGI程序。CGI程序通过文件信息表中Md5值的比较,判断当前文件信息是否存在于数据库中,如果存在则将该文件信息与该用户通过user_file_list表进行关联,否则返回数据库无该文件信息的状态码。客户端接受到状态码后进行判断,成功则不需再进行上传操作,即实现了秒传,否则需要进一步进行上传操作。

img

图4-6 数据秒传流程图

上传过程需要客户端维护一个上传队列。客户端选择文件路径后,每次对于确定无法秒传需要上传的文件信息假如到上传队列中。上传时每次从队列中提取队首元素进行请求,上传完成时将该任务从队列中移除。该过程客户端会时时跟进上传进度,并且将进度按进度条的形式更新在数据传输列表界面。

开始上传时,客户端获取到该文件后将文件以二进制流的形式进行HTTP传输。服务端通过请求头upload将用户信息与数据交给相应端口的CGI程序。CGI程序逻辑为首先通过数据库file_info表判断该文件是否存在,若存在则判断该用户是否拥有,是则反馈已拥有状态码,负责对user_file_list与user_file_count表进行修改操作。否则会通过fork创建子进程,子进程将数据上传到分布式文件系统,通过fdfs_upload_file的API将提取出的二进制流文件上传到分布式文件系统,同时获取到分布式文件系统反馈的文件id,让id传给父进程。父进程用于处理数据信息,将文件生成后的信息插入到file_info表中,同时将用户与文件但关联信息插入到user_file_list中,同时对user_file_count表进行更新。文件信息处理好后,给用户反馈成功状态码。在父子进程的过程中任意一步出现问题均反馈失败状态码。客户端接收到状态码后,通过状态码比对,如果是成功状态码则向用户反馈上传成功的信息,否则给用户反馈上传失败的信息。

img

图4-7 数据上传流程图

4.3.4 文件删除

当用户请求删除操作时,客户端首先需要进行判断用户请求的文件拥有者是否为该用户,如果不是则提示文件不属于该用户的错误信息;否则向服务端发起请求。服务端接收到请求后,通过请求头dealfile或者dealsharefile将用户信息与数据交给相应端口用于文件操作的CGI程序,CGI程序进行处理。CGI程序的逻辑为首先进行数据库查询,首先对user_file_count表进行减一操作,对user_file_list中该用户与该文件的关联进行删除。最后需要通过file_info表的数量属性进行判断,如果大于1,则将该属性减1,否则将该信息从数据库file_info表中删除。同时子进程需通过分布式文件系统提供的fdfs_delete_file相关API对通过该文件Id删除分布式文件系统中该文件的数据。一切成功后向客户端反馈状态码。客户端收到反馈后刷新界面。

img

图4-8 文件删除流程图

4.3.5 文件共享与共享列表查询

当用户切换到共享文件界面时,会向服务端发起共享文件列表获取的请求,通过share_file_list表进行共享文件信息的查询,然后将查询到的列表信息发送给客户端。客户端接收到数据后对界面按照图标显示的方式进行刷新。对下载榜界面,服务端会将文件按下载量进行排序,然后发给客户端,客户端通过信息列表的形式进行显示。

当用户发起共享或者取消共享操作后,客户端逻辑首先进行判断用户发起的请求文件是否属于该用户,不是的话反馈错误信息;是的话需要根据该文件信息判断该文件分享状态,如果已是该状态则不需操作,否则会向服务端发起请求。当服务端接收到请求后,通过请求头dealfile或者dealsharefile将用户信息与数据交给相应端口用于文件操作的CGI程序,CGI程序的逻辑为首先提取数据,对数据库share_file_list表进行插入,然后对file_info表等文件相关的表进行更新。最后反馈状态码。

img

图4-9 文件共享流程图

4.3.6 数据下载

下载模块首先需保证服务端存储结点Storage与Web处理服务器Nginx相关联,关联后对于存储结点上的数据可直接通过Url进行下载。客户端维护一个下载队列。而下载的流程主要是用户发起下载请求后,客户端会向服务器请求该文件Url信息,收到文件Url后,客户端将下载信息插入下载队列。客户端每次执行队首任务,根据下载信息向相应Url进行Get请求,请求成功后便开始数据下载,同时对于下载进度通过进度条时时更新在数据传输列表界面上。当下载完成时,将该任务从下载队列中移除,然后进行下一个文件下载。

img

图4-10 文件下载流程图

4.3.7 图像预览

由于用户进入文件界面后,客户端代码会将当前缓存中的文件数据保存起来,因此当用户点击预览按钮时,首先客户端会判断该文件信息的类型,如果为图像文件方可进行预览操作,否则反馈失败信息。客户端根据当前保存的文件信息进行Url获取,同时通过HTTP协议对该Url进行请求,获取到响应后客户端会通过QLable进行图像的绘制,为用户呈现该图像的完整状态。同时客户端会将该图像文件缓存起来,以便下次再次访问该图像文件时直接对缓存中的数据进行绘制,而不需在向服务器进行请求。

img

图4-11 图像预览流程图

4.4 流程关系

本项目的流程并不是很复杂,但是由于涉及到的东西较多,因此整个项目流程的清晰度决定了项目实现的难易。

4.4.1 客户端流程

客户端流程分为用户界面流程与文件界面流程两部分。用户通过可执行文件首先加载的是用户界面,通过用户界面的设置栏设置反向代理服务器的IP与端口号,客户端程序保存IP与端口号,之后将所有相关数据发送对于发现代理服务器IP。设置完成后,用户可选择性通过注册栏发送注册信息给服务端,收到服务端注册成功的反馈后跳转至登录界面。用户通过登录界面填写用户名及密码,点击登录后,获取服务端的反馈信息,校验成功则跳转文件界面,否则提示登录失败。

进入文件界面后,默认在我的文件界面,客户端会向服务端发送当前用户信息以及获取当前用户拥有文件信息,得到服务端反馈的信息后,客户端代码将其文件信息绘制到UI界面上,同时如果本地缓存中有相应文件的缓存缩略图,则将默认显示图像替换为缩略图图像,实现预览效果。

文件界面默认主界面有上传按钮,点击后可选择指定文件夹下的一个或多个图像文件进行上传操作,然后会切换到文件界面的传输列表界面。文件主界面空白域右键点击事件包括文件重新排序与上传等操作,其中上传操作与点击上传按钮事件一样。文件默认展示文件类型图像,如果该文件为图像文件且缓存中有该文件的缩略图,则以缩略图的方式显示。文件右键点击事件包括下载、共享、预览、删除、属性等点击事件,对应下载、共享、预览、删除、属性操作。

文件界面包含主界面、共享文件界面、下载榜界面、传输列表界面四部分,在UI头部有相应切换事件响应的按钮。

共享文件界面与下载榜界面的流程与主界面的流程相似,唯一不同的是向服务端请求的是共享文件信息而不是用户文件信息。共享文件界面与下载榜界面的不同在于排列方式不同以及文件信息显示方式不同,共享文件界面的排列方式为按共享时间顺序排列,同时以图标的形势显示文件;而下载榜是以文件下载量的方式进行排序,以详细信息的方式进行显示。

传输列表包含上传列表、下载列表、传输记录三部分,对应上传进度、下载进度、上传下载记录三部分的展示。

主界面同时包含切换用户按钮,点击后跳转登录界面。

img

图4-12 客户端总体流程图

4.4.2 服务端流程

服务端整体的流程包括数据转发、数据提取、分布式文件系统操作、数据库操作四部分。

首先数据转发部分主要流程是反向代理服务器接收到数据后根据并发权重将数据转发给Web服务器,Web服务器通过配置文件与HTTP请求头信息进行类型解析,根据不同的类型将数据发送给不同的端口所绑定的CGI程序。

数据提取主要为服务端公共代码的任务,将Json数据中的信息提取出来,然后供CGI程序进行响应一系列执行操作。

分布式文件系统通过FastDFS提供的API对数据对象进行上传、下载、删除操作。在此之前需要服务器先搭建好分布式文件系统的集群。由于FastDFS为C语言所写,因此安装后的API直接可以用到服务端C++程序中。

数据库操作主要分为两部分,一部分是通过MySQL进行数据的增删改查,另一部分是对访问量较多的数据储存于Redis[26]。所有程序在对数据库进行操作时,首先会从缓存数据库Redis中查询,如果缓存数据库中已有该数据,则直接获取,否则会从MySQL中进行查询,然后在处理数据的过程中将数据同时插入缓存数据库中。

服务端从功能部分大致分为用户登录与注册、文件上传或删除、文件共享与转存、文件下载与预览几部分。这些功能模块均首先通过数据转发后进行数据提取,然后进行各类型的一系列操作。

用户登录与注册部分主要为数据库操作;文件上传或删除包括分布式文件系统操作与数据库操作两部分;文件的共享与转存操作并未涉及到分布式文件系统操作,主要为数据库操作。

文件下载与预览部分有两种实现方式,第一种也是常规的方式包括分布式文件操作与数据库操作,但这样每次会造成效率的低下,因此通过第三方软件将存储结点Storage与Nginx连接,使得存储结点的数据可直接以Url的方式进行获取,这样只需要进行数据库操作即可,即将Url保存至数据库中,而数据的获取直接通过Url便可下载,而不需经过分布式文件系统追踪器等一系列过程。

img

图4-13 服务端总体流程图

5 具体实现

5.1 服务端架构实现

5.1.1 负载均衡

Nginx负载均衡是在反向代理的基础上完成的,首先用户通过浏览器或者客户端连接到Nginx反向代理服务器,Nginx通过配置文件中的server模块找到server_name映射的域名,通过proxy_pass+Url找到upstream模块,然后访问server相应的地址。upstream模块中可设置多个IP,同时赋予权重,每次用户访问服务器时,Nginx都会按权重将用户请求分配到upstream模块中对应的IP,这样便实现了负载均衡。

负载均衡通过配置Nginx.conf实现[27]。具体负载均衡部分配置样例如下:

upstream test.com{

server 39.96.209.253:80; #服务器1

server 172.17.49.222:80; #服务器2

}

server{

listen 80;

server_name localhost;

Location /{

proxy_pass HTTP://test.com;

}

}

5.1.2 数据库设计

数据库主要用于存储用户与文件的信息,数据信息存于MySQL中。数据库表主要分为五张表,具体表结构如下图所示:

img

图5-1 数据库表结构

user表用于储存用户相关信息。当用户注册时将信息插入该表中;当用户登录时通过查询该表进行用户身份校验,校验成功方能进入文件界面对图像进行管理。user表中包含name、nickname、password、phone、createtime、email六个栏位,其中name作为用户名,password作为密码,用于登录时校验,其余作为用户信息储存栏位。

表5-1 user表

序号 列名 数据类型 长度 主键 允许空 备注
1 name varchar 20 用户id
2 nickname varchar 20 用户昵称
3 password varchar 65 用户密码
4 phone varchar 12 电话
5 createtime datetime 0 注册时间
6 email varchar 30 邮箱

file_info表用于储存文件信息。该表包括md5、file_id、url、size、type、count六个栏位。md5作为文件的唯一标识,也可认为是文件的唯一id标识;file_id用于储存文件在分布式文件系统中对应的id即文件名,可通过该id从分布式文件系统中下载文件;url用于储存该文件的获取网址;size用于记录文件的大小;type代表该文件类型;count用于统计有多少用户拥有该文件,主要用于文件删除。

表5-2 file_info表

序号 列名 数据类型 长度 主键 允许空 备注
1 md5 varchar 65 文件id
2 file_id varchar 100 对象存储id
3 url varchar 100 文件url
4 size bigint 20 文件大小
5 type varchar 10 文件类型
6 count int 11 拥有者数量

user_file_list作为用户与文件的关系桥梁而存在。表共包含user、md5、createtime、filename、shared_status、pv六栏。user代表用户id;md5代表文件id;createtime代表用户拥有该文件的时间;filename代表用户拥有该文件时的文件名;share_status用于表示该文件的分享状态;pv表示该用户对该文件的下载次数。

表5-3 user_file_list表

序号 列名 数据类型 长度 主键 允许空 备注
1 user varchar 20 用户id
2 md5 varchar 65 文件id
3 createtime datetime 0 关联时间
4 filename varchar 100 文件名称
5 shared_status int 11 分享状态
6 pv int 11 下载量

share_file_list表记录共享文件的信息。包括user、md5、createtime、filename、pv五个栏位。user代表该文件的分享者;md5代表该文件id;createtime代表分享时间;filename代表该文件被分享时的文件名;pv代表该文件全部的下载次数。

表5-4 share_file_list表

序号 列名 数据类型 长度 主键 允许空 备注
1 user varchar 65 分享用户id
2 md5 varchar 65 分享文件id
3 createtime datetime 0 分享时间
4 filename varchar 100 文件名称
5 pv int 11 下载量

user_file_count表主要记录用户当前拥有多少个文件。其主要用于文件列表获取前访问,如果文件列表数量庞大,需先访问用户文件数目,再分批访问。该表共user、count两个栏位。user代表用户id;count代表该用户拥有文件数量。

表5-5 user_file_count表

序号 列名 数据类型 长度 主键 允许空 备注
1 user varchar 20 用户id
2 count int 11 用户文件数

5.1.3 文件对象存储

数据对象本身存储与分布式文件系统中。在服务器上安装好FastDFS分布式文件系统后,需要修改配置文件。由于FastDFS分布式文件系统包括追踪器、存储节点、客户端三部分,因此需要修改tracker.conf、storage.conf、client.conf三个配置文件。

先配置Tracker,再添加一个Storage,每添加添加一个Storage,实际上是Storage连接Tracker,Tracker必须存在,否则Storage无法加进来,Client主要用于测试上传、下载文件。

假如有3台以上的服务器或者虚拟机,一台用来作为Tracker、一台用来作为Client、其他多台用来作为Storage,不过前提需要保证这些服务器之间的网络均可以互相PING通。如果并没有足够多的设备,一台服务器可以同时作为Tracker、Storage、Client使用。

首先是tracker.conf的配置,追踪器服务器需要修改,其他服务器可以不用配置。bind_addr需要修改为追踪器服务器所在的IP,port修改为绑定的端口, base_path为日志目录,配置样例如下:

bind_addr=39.96.209.253

port=22122

base_path=/home/fastdfs/tracker

作为存储节点的服务器需要修改storage.conf,主要修改以下部分。group_name表示存储节点所属的组;bind_addr表示存储节点绑定的IP;port为存储节点绑定的端口;base_path表示存储日志目录;store_path_count配置存储目录的个数;store_path0配置具体的存储目录;tracker_server用于配置连接Tracker的时候使用的IP和端口;配置样例如下:

group_name=group1

bind_addr=39.96.209.253

port=23000

base_path=/home/fastdfs/storage

store_path_count=1

store_path0=/home/fastdfs/storage

tracker_server=39.96.209.253:22122

客户端服务器主要通过API请求上传、下载等操作。因此所有用于响应用户请求的HTTP服务器均需对文件client.conf进行配置。主要需要修改两部分:base_path配置日志目录;tracker_server配置连接Tracker服务器时使用的IP和端口。Client配置样例如下:

base_path=/home/fastdfs/client

tracker_server=39.96.209.253:22122

配置文件配置完成后,所有响应请求的HTTP服务器通过Client调用API向Tracker请求上传、下载等操作[28]。对于常用的API,可通过源码的方式获取。文件上传调用fdfs_upload_file,下载调用fdfs_download_file,删除调用fdfs_delete_file[29]。因此对于数据上传、下载或删除请求,我们可以通过加载fdfs_upload_file.c,fdfs_download_file.c,fdfs_delete_file.c获取对应操作的API。

5.2 客户端架构实现

5.2.1 用户界面设计

客户端界面分为两部分,用户界面与文件界面。其中用户界面为一个主界面包含注册、登录、设置三个子界面。而文件界面由按钮栏和文件列表栏两部分拼凑而成,文件列表栏作为父类有我的文件界面、共享列表界面、下载榜列表界面和传输列表界面四个派生类,通过按钮栏的点击事件通过信号槽触发回调函数,创建不同的文件列表栏派生类。

用户界面由一个主界面Login类构成,该类由信息栏title_widget与表单栏stackedWidget两部分组成。信息栏主要用于图标、标题等固定信息的展示;表单栏包含三个QWidget子界面login_page、register_page与set_page,分别用于登录、注册与设置。具体结构如下图:

img

图 5-2 用户界面结构

当触发切换界面按钮事件时,通过信号槽触发回调函数,通过回调函数调用setCurrentWidget(…)方法根据传参子界面参数进行不同界面的切换。用户界面类的声明如下:

class Login : public QDialog{

​ Q_OBJECT

public:

​ explicit Login(QWidget *parent = 0);

​ ~Login();

​ // 设置登陆用户信息的Json包

​ QByteArray setLoginJson(QString user, QString pwd);

​ // 设置注册用户信息的Json包

​ QByteArray setRegisterJson(QString userName, QString nickName, QString firstPwd, QString phone, QString email);

​ // 得到服务器回复的登陆状态, 状态码返回值为 “000”, 或 “001”,还有登陆section

​ QStringList getLoginStatus(QByteArray json);

protected:

​ void paintEvent(QPaintEvent *);

private slots:

​ void on_register_btn_clicked();

​ void on_login_btn_clicked();

​ void on_set_ok_btn_clicked();

private:

​ // 读取配置信息,设置默认登录状态,默认设置信息

​ void readCfg();

private:

​ Ui::Login *ui;

​ // 处理网络请求类对象

​ QNetworkAccessManager* m_manager;

​ // 主窗口指针

​ MainWindow* m_mainWin;

​ Common m_cm;

};

其登录主界面效果展示如下:

img

图5-3 登录界面效果图

用户进入登录界面后,通过点击注册,进入注册界面,点击关闭会返回登录界面。其注册界面效果展示如下:

img

图5-4 注册界面效果图

5.2.2 文件界面设计

文件界面作为文件基础界面,在用户点击登录按钮后启动。文件界面分为导航栏ButtonGroup类与文件列表界面MainWindow类两部分组成。结构如下:

img

图5-5 文件界面结构

文件列表界面MainWindow中包含ButtonGroup指针,在启动界面时会通过指针先加载导航栏ButtonGroup类。导航栏由我的文件、共享列表、下载榜、传输列表、切换用户5个界面切换按钮以及关闭之类的基础按钮组成,通过信号槽分别对应不同回调函数。其回调函数声明在signals中。ButtonGroup类声明代码声明如下:

class ButtonGroup : public QWidget{

​ Q_OBJECT

public:

​ explicit ButtonGroup(QWidget *parent = 0);

​ ~ButtonGroup();

public slots:

​ // 按钮处理函数

​ void slotButtonClick(Page cur);

​ void slotButtonClick(QString text);

​ void setParent(QWidget *parent);

….

signals:

​ void sigMyFile(); //我的文件信号

​ void sigShareList(); //共享文件信号

​ void sigDownload(); //下载榜信号

​ void sigTransform(); //传输列表信号

​ void sigSwitchUser(); //切换用户信号

​ void closeWindow(); //关闭信号

​ void minWindow(); //最小化信号

​ void maxWindow(); //最大化信号

private:

​ Ui::ButtonGroup *ui;

​ QPoint m_pos;

​ QWidget* m_parent;

​ QSignalMapper* m_mapper;

​ QToolButton* m_curBtn;

​ QMap<QString, QToolButton*> m_btns;

​ QMap<Page, QString> m_pages; //文件列表界面及名称

};

导航栏ButtonGroup 效果界面展示图如下:

img

图5-6 文件界面导航栏

文件列表MainWindow作为父类共包含我的文件界面MyFileWg类、共享列表界面ShareList类、下载榜界面RankingList类和传输列表界面Transfer类四个派生类,这四个界面均继承自MainWindow类。通过不同的按钮触发信号槽对应的回调函数绘制不同的子界面。

文件列表界面父类MainWindow具体声明代码如下:

class MainWindow : public QMainWindow{

​ Q_OBJECT

public:

​ explicit MainWindow(QWidget *parent = 0);

​ void showMainWindow(); // 显示主窗口

​ void managerSignals(); // 处理信号

​ void loginAgain(); // 重新登陆

signals:

​ void changeUser(); // 切换用户按钮信号

protected:

​ void paintEvent(QPaintEvent *event);

private:

​ Ui::MainWindow *ui; //文件界面指针

​ Common m_common; //工具类

};

img

图5-7 我的文件效果图

img

图5-8 共享列表效果图

img

图5-9 下载榜效果图

img

图5-10 传输列表效果图

5.2.3 基础功能模块

客户端在进行界面设计的同时为了避免代码冗余,需要对一些比较常用的方法进行抽离,实现高内聚低耦合。因此将这些常用的方法封装成工具类,放在Common文件夹里。该文件夹包含基础类文件和工具类文件。基础类汇集在common.cpp,工具类包括Md5加密算法des.c、用户信息保存logininfoinstance.cpp、下载任务列表downloadtask.cpp、下载进度界面downloadlayout.cpp、上传任务列表uploadtask.cpp、上传进度界面uploadlayout.cpp。

基础类头文件common.h包含宏定义配置,包括配置文件的宏定义与正则表达式的宏定义,同时包括文件类的属性声明。基础类Common包括读写配置文件、读写日志、文件类型判断、Md5加密、HTTP通信、获取状态码等方法的实现。具体声明如下:

class Common : public QObject{

​ Q_OBJECT

public:

​ Common(QObject* parent = 0);

​ ~Common();

​ // 窗口在屏幕中央显示

​ void moveToCenter(QWidget *tmp);

​ // 从配置文件中得到相对应的参数

​ QString getCfgValue(QString title, QString key, QString path = CONFFILE);

​ // 通过读取文件, 得到文件类型, 存放在typeList

​ void getFileTypeList();

​ // 得到文件后缀,参数为文件类型,函数内部判断是否有此类型,如果有,使用此类型,没有,使用other.png

​ QString getFileType(QString type);

​ // 登录信息,写入配置文件

​ void writeLoginInfo(QString user, QString pwd, bool isRemeber, QString path = CONFFILE);

​ // 服务器信息,写入配置文件

​ void writeWebInfo(QString ip, QString port, QString path=CONFFILE);

​ // 获取某个文件的Md5码

​ QString getFileMd5(QString filePath);

​ // 将某个字符串加密成Md5码

​ QString getStrMd5(QString str = “”);

​ // 产生分隔线

​ QString getBoundary();

​ // 得到服务器回复的状态码, 返回值为 “000”, 或 “001”

​ QString getCode(QByteArray json);

​ // 传输数据记录到本地文件,user:操作用户,name:操作的文件, code: 操作码, path: 文件保存的路径

​ void writeRecord(QString user, QString name, QString code, QString path = RECORDDIR);

​ // 得到HTTP通信类对象

​ static QNetworkAccessManager* getNetManager();

public:

​ static QStringList m_typeList;

private:

​ // 文件类型路径

​ static QString m_typePath;

​ static QNetworkAccessManager *m_netManager;

};

其配置反向代理服务器IP与端口的设置界面如下:

img

图5-11 配置设置效果图

工具类LoginInfoInstance为单例模式,当用户信息确认后会将当前用户信息与服务器信息保存到堆中,每次当需要获取用户信息或服务器信息时直接从堆中获取。

工具类中下载任务列表DownloadTask、下载进度界面DownloadLayout、上传任务列表UploadTask、上传进度界面UploadLayout均采用单例设计模式。

Layout作为客户端界面,当客户端访问数据传输列表界面时会加载该单例模式界面。其界面如下:

img

图5-12 任务进度图

Task作为任务,维护一个队列,当有任务时会将任务插入队列中,每次提取队首任务进行上传、下载操作。当任务完成时从队列中删除该任务。以上传任务为例,其界面效果图如下:

img

图5-13上传任务界面效果图

5.3 功能模块实现

5.3.1 数据封装与提取

由于客户端跟服务端数据之间需要不断交互,但客户端和服务端无论在操作系统还是开发工具上都截然不同,因此数据需要采用统一的格式去存储。而Json作为跨平台的数据交互方式,因此可以将数据封装成Json格式,进行交互。

封装与提取的过程由于客户端与服务端的开发工具不同因此实现方式也不同。首先对于服务端,cJSON是由纯C实现的,跨平台性较好。cJSON是采用链表存储的。

cJSON库在使用时只需两步:将cJSON.c和cJSON.h添加到项目即可;如果在命令行进行链接还需加上-lm表示链接math库[30]。

对于客户端,由于Qt将C++封装成了一套专属于Qt的语言,同时有一套自己的框架,因此对于Json的处理Qt有操作Json数据的中心类QJsonDocument。因此对于解析Json数据只需调用API即可,而对于封装Json数据的方法代码如下:

void Common::writeWebInfo(QString ip, QString port, QString path){

​ // Web_server信息

​ QMap<QString, QVariant> web_server;

​ web_server.insert(“ip”, ip);

​ web_server.insert(“port”, port);

​ // type_path信息

​ QMap<QString, QVariant> type_path;

​ type_path.insert(“path”, m_typePath);

​ // login信息

​ QString user = getCfgValue(“login”, “user”);

​ QString pwd = getCfgValue(“login”, “pwd”);

​ QString remember = getCfgValue(“login”, “remember”);

​ QMap<QString, QVariant> login;

​ login.insert(“user”, user);

​ login.insert(“pwd”, pwd);

​ login.insert(“remember”, remember);

​ QMap<QString, QVariant> json;

​ json.insert(“web_server”, web_server);

​ json.insert(“type_path”, type_path);

​ json.insert(“login”, login);

​ QJsonDocument jsonDocument = QJsonDocument::fromVariant(json);

​ file.write(jsonDocument.toJson());

​ file.close();

}

5.3.2 用户登录与注册

对于用户部分,除了客户端界面以外,服务端的实现主要是对于数据库的操作,首先Web服务器Nginx将登录请求交由10000端口CGI程序进行处理,将注册请求交由10001端口CGI程序进行处理,需要配置如下:

location /login{

fastcgi_pass 127.0.0.1:10000;

include fastcgi.conf;

}

location /reg{

fastcgi_pass 127.0.0.1:10001;

include fastcgi.conf;

}

Shell命令需要将端口与CGI程序绑定,脚本如下:

spawn-fcgi -a 127.0.0.1 -p 10000 -f ./bin_cgi/login

spawn-fcgi -a 127.0.0.1 -p 10001 -f ./bin_cgi/register

通过配置文件将数据传递给对应端口的CGI程序,登录模块的核心部分是数据库信息的比对与结果的封装,数据封装通过数据处理模块完成,而核心的SQL操作语句如下:

sprintf(sql_cmd, “select password from user where name=\”%s\””, user);

注册部分对于数据库操作的核心代码如下:

sprintf(sql_cmd, “insert into user (name, nickname, password, phone, createtime, email) values (‘%s’, ‘%s’, ‘%s’, ‘%s’, ‘%s’, ‘%s’)”, user, nick_name, pwd, tel, time_str ,email);

5.3.3 数据上传模块(上传、秒传)

文件上传分为秒传与上传,秒传是对于服务端已有该文件的情况下无需再对文件进行分布式文件系统存储,而直接更改数据库,上传则需要将文件上传到分布式文件系统,

对于客户端的上传请求,首先客户端将上传请求插入到上传队列里,对于完成的请求从队列中删除。

当第0号任务开始进行上传工作时,客户端将文件信息封装后向服务器发起秒传请求,服务端接收到请求后对请求头进行判断,如果是Md5,则将数据信息传给10003端口绑定的CGI程序。CGI程序对数据库进行查询,如果有该文件信息,则直接更改数据库,通过file_info表将文件信息和该用户信息相关联,然后反馈成功状态码。否则反馈失败状态码。Web服务器Nginx需要配置如下:

location /Md5{

​ fastcgi_pass 127.0.0.1:10003;

​ include fastcgi.conf;

}

Shell命令需要将端口与CGI程序绑定,脚本如下:

spawn-fcgi -a 127.0.0.1 -p 10003 -f ./bin_cgi/Md5

客户端接收到服务端的反馈信息后,如果状态码提示服务器没有该文件,则意味着无法秒传,需继续进行数据上传操作。客户端向服务端发送请求:

QNetworkReply * reply = m_manager->post( request, data );

if(reply == NULL){

​ cout << “reply == NULL”;

​ return;

}

服务端接收到Post请求后对请求头进行判断是否为upload,将数据信息传给10002端口绑定的CGI程序。CGI程序对数据库进行添加文件信息操作,同时通过fdfs_upload_file提供的API将数据信息上传到服务器分布式文件系统中。Web服务器Nginx需要配置如下:

location /upload{

fastcgi_pass 127.0.0.1:10002;

include fastcgi.conf;

}

Shell命令需要将端口与CGI程序绑定,脚本如下:

spawn-fcgi -a 127.0.0.1 -p 10002 -f ./bin_cgi/upload

客户端的数据传输列表界面时时跟进当前的上传进度,当有可用数据更新时,会刷新界面。跟进的信号槽代码如下:

connect(reply, &QNetworkReply::uploadProgress, ={

​ if(totalBytes != 0) {

​ dp->setProgress(bytesRead/1024, totalBytes/1024); //设置进度条

​ }

});

5.3.4 文件查询模块(文件列表、共享列表、下载榜)

对于客户端的请求,首先Web服务器Nginx将文件信息请求交由10004端口CGI程序进行处理,将共享列表请求交由10006端口CGI程序进行处理,需要配置如下:

location /myfiles{

fastcgi_pass 127.0.0.1:10004;

include fastcgi.conf;

}

location /sharefiles{

fastcgi_pass 127.0.0.1:10006;

include fastcgi.conf;

}

Shell命令需要将端口与CGI程序绑定,脚本如下:

spawn-fcgi -a 127.0.0.1 -p 10004 -f ./bin_cgi/myfiles

spawn-fcgi -a 127.0.0.1 -p 10006 -f ./bin_cgi/sharefiles

对于CGI程序,文件信息与共享文件分别交给myfiles.c与sharefiles.c处理。以myfiles.c为例,首先会对数据提取的信息状态进行比对,判断具体请求,比如下载榜需将请求数据排序。对于文件信息列表请求的数据库核心代码如下:

sprintf(sql_cmd, “select user_file_list.*, file_info.Url, file_info.size, file_info.type from file_info, user_file_list where user = ‘%s’ and file_info.Md5 = user_file_list.Md5 limit %d, %d”, user, start, count);

5.3.5 文件处理模块(删除、共享、转存)

对于客户端的删除、共享、取消共享、转存等请求,首先Web服务器Nginx将文件信息请求交由10004端口CGI程序进行处理,将共享列表请求交由10006端口CGI程序进行处理,需要配置如下:

location //dealfile{

fastcgi_pass 127.0.0.1:10005;

include fastcgi.conf;

}

location //dealsharefile{

fastcgi_pass 127.0.0.1:10007;

include fastcgi.conf;

}

Shell命令需要将端口与CGI程序绑定,脚本如下:

spawn-fcgi -a 127.0.0.1 -p 10005 -f ./bin_cgi/dealfile

spawn-fcgi -a 127.0.0.1 -p 10007 -f ./bin_cgi/sharefiles

对于CGI程序,需要将文件划分为普通文件与共享文件,普通文件可直接操作,而共享文件需要进行判断共享文件拥有者。普通文件与共享文件的处理分别交给dealfile.c与sharefiles.c处理。以dealfile.c为例,首先会对数据请求类型进行判断,请求类型具体分为删除、分享、取消分享、转存等类型,四者均对数据库进行增删改查操作,只有删除操作在确认该文件拥有者为0时会对分布式文件系统中的文件进行删除,具体删除FastDFS中文件的核心代码如下:

int remove_file_from_storage(char *fileid){

​ int ret = 0;

​ //读取fdfs client 配置文件的路径

​ char fdfs_cli_conf_path[256] = {0};

​ get_cfg_value(CFG_PATH, “dfs_path”, “client”, fdfs_cli_conf_path);

​ char cmd[1024*2] = {0};

​ sprintf(cmd, “fdfs_delete_file %s %s”, fdfs_cli_conf_path, fileid);

​ ret = system(cmd);

​ return ret;

}

5.3.6 数据下载模块

由于服务器端存储结点Storage与Nginx关联,因此存储在存储结点的数据可直接通过Url的方式进行获取,提高了服务端下载的效率。对于客户端,维护一个静态队列,队列中存储需要下载的任务信息。每次移除已经下载完成的任务,将最新下载请求进行数据封装后插入下载队列。当队列第0个任务元素需要下载时,首先通过该文件Url发起HTTP请求,具体Get请求代码如下:

QNetworkReply * reply = m_manager->get( QNetworkRequest(Url) );

if(reply == NULL){

​ p->dealDownloadTask(); //删除任务

​ cout << “get err”;

​ return;

}

获取请求的数据完成时,就会发送信号SIGNAL(finished()),代码如下:

connect(reply, &QNetworkReply::finished, ={

​ cout << “下载完成”;

​ reply->deleteLater();

p->dealDownloadTask();//删除下载任务

m_cm.writeRecord(user, filename, “010”); //下载文件成功,记录

dealFilePv(Md5, filename); //下载文件pv字段处理

});

reply在有数据时发出readyRead信号,我们便可保存数据。具体代码如下:

connect(reply, &QNetworkReply::readyRead, ={

​ if (file != NULL){

​ file->write(reply->readAll());

​ }

});

有可用数据更新时,会通过信号槽刷新进度界面,代码如下:

connect(reply, &QNetworkReply::downloadProgress, ={

​ dp->setProgress(bytesRead, totalBytes);//设置进度

});

5.3.7 图像预览模块

由于图像Url信息保存在数据库中,而在文件列表请求的过程中会默认将Url保存到文件信息中,因此对于图像预览,需要根据传进来不同的Url参数进行请求。首先创建QNetworkAccessManager进行HTTP通信,然后建立信号连接槽,通过Get的方式向Url发起请求。流程如下:

void PreviewImg::load_network_img(QString Url){

​ currentPicture = new QPixmap;

​ //获取网络图片

​ QNetworkAccessManager *manager;

​ manager = new QNetworkAccessManager(this);

​ connect(manager, SIGNAL(finished(QNetworkReply*)),

​ this, SLOT(replyFinished(QNetworkReply*)));

​ manager->get(QNetworkRequest(QUrl( Url )));

}

当请求完成时会调用完成回调函数,绘制预览图像界面,同时如果用户选择缓存图片,则会对缩略图及缓存图片进行本地缓存,之后访问直接先通过缓存加载图像,加快下一次访问时的效率。回调函数如下:

void PreviewImg::replyFinished(QNetworkReply *reply){

​ if (reply->error() == QNetworkReply::NoError){

​ currentPicture->loadFromData(reply->readAll());//获取字节流QPixmap对象

​ QString filename = cachePathFile;

​ currentFileName = filename;

​ if(flag){//true预览图片,false加载缩略图

​ showImgFile(currentPicture);//加载预览界面

​ }else{

​ PreviewImg::isTask = false;//缩略图请求任务结束

​ }

​ if(isCache){ //是否缓存图片

​ currentPicture->save(cachePathFile);//保存图片

​ saveIcoFile(currentPicture);//保存缩略图

​ }

​ }

}

img

图5-14 图像预览列表图

6 测试

6.1 程序调试

任何项目在开发过程中均或多或少会遇到各种各样的错误,除了比较基础的配置环境问题或语法错误以外,还有很多问题是在程序运行的过程中才能发现的。因此在程序设计的同时,尽量使每个模块独立,减少文件之间因耦合度过高而出现错误的几率,达到高内聚低耦合的效果,这样在每个模块设计完成的同时可以独立测试,方便排查错误,提高修复错误的效率。

在程序调试的程序的过程中,服务端主要通过Linux自带的GDB工具进行断点调试,排查错误语法;客户端主要通过Qt Creator语法错误提示和Debug断点单步调试,迅速定位错误代码并显示错误信息。

6.2 工具测试

6.2.1 测试的目的和意义

软件测试重点在于在真实的软件运行环境下通过与软件需求进行比较,发现软件与需求有所偏差的地方。

此次软件测试的目的在于检查基于云存储的图像管理平台已完成的功能,发现软件在运行过程中出现的错误并及时解决,使软件能正常运行,确保每个功能可以正常使用,同时尽量保证软件的功能基本符合软件需求。

6.2.2 测试框架

QTestLib为用户提供了一个操作简便的单元测试框架,因此本次测试使用Qt Creator 自带的单元测试框架QTestlib进行测试。

6.2.3 测试步骤

本平台的设计步骤通过断点调试、单元测试、集成测试、系统测试四部分对系统的功能和性能进行检查和完善[31]。

首先是单元测试,单元测试以功能模块或函数作为对象,通常采用白盒测试技术,辅以黑盒技术,集中地对程序所实现的每个功能模块进行测试,竭力覆盖每个函数,检验各个程序模块是否存在问题,与所描述的功能是否相符合。

其次是集成测试,把已通过单元测试完成的模块进行组合,最终组成所预期的平台系统。其作用主要是检验软件体系的结构是否合理,检查接口之间的问题。

最后是系统测试,把已经集成测试的软件纳入实际运行环境中,与硬件、外设等支持软件运行的系统因素组合,进行环境相关的测试。

6.3 测试用例设计

QTestLib为用户提供了一个操作简便的单元测试框架,使用时可以通过在新建项目栏点击其他项目-Qt单元测试,也可以直接在工程文件里加入语句Qt+=testlib。其基本操作代码如下:

class Untitled2Test : public QObject {

Q_OBJECT

public:

Untitled2Test();

private Q_SLOTS:

void initTestCase();

void cleanupTestCase();

void testCase1();

};

Untitled2Test::Untitled2Test() {

}

void Untitled2Test::initTestCase() {

}

void Untitled2Test::cleanupTestCase() {

}

void Untitled2Test::testCase1() {

QVERIFY2(true, “Failure”);

}

QTEST_APPLESS_MAIN(Untitled2Test)

#include “tst_untitled2test.moc”

其中,首个测试函数执行前调用initTestCase();最后一个测试函数执行后调用cleanupTestCase();每个测试函数执行前调用init();每个测试函数执行后调用cleanup()[32]。

对于GUI相关的操作,Qtestlib同样提供了接口。通过对控件传递信息来检查结果。常用的操作函数例如鼠标的点击事件QTest::mouseClick(),以及键盘的点击事件QTest::keyClick()[33]。

img

图6-1 GUI单元测试部分结果

6.4 测试数据及结果

6.4.1 功能测试数据及结果

功能测试通过对平台已实现的功能进行单元测试与集成测试,查看功能在运行状况下是否与预期的功能效果相符,同时查找在单步调试中未发现而在程序运行中会出现的潜在错误。以下是功能测试数据及结果。

表6-1 功能测试结果

功能模块 前置条件 测试步骤 预期结果 实测结果
设置测试-IP 进入设置界面 IP输入不规范 提示IP不正确 提示IP不正确
设置测试-端口 进入设置界面 端口输入不规范 提示端口不正确 提示端口不正确
设置测试-集成测试 进入设置界面 IP与端口输入均符合规范 自动跳转至登录界面 自动跳转至登录界面
设置测试-集成测试 进入注册界面,信息输入正确 未设置端口和IP 提示注册连接失败 提示注册连接失败
设置测试-集成测试 进入登录界面,信息输入正确 未设置端口和IP 提示登录连接失败 提示登录连接失败
用户注册测试-必填项 进入用户注册页面 信息栏为空,点击注册 提示用户注册信息为空 提示用户注册信息为空
用户注册测试-边界值 进入用户注册页面 输入用户名不规范,其他信息规范 提示注册失败 提示用户名不正确
用户注册测试-边界值 进入用户注册页面 输入昵称不规范,其他信息规范 提示注册失败 提示昵称不正确
用户注册测试-边界值 进入用户注册页面 输入密码不规范,其他信息规范 提示注册失败 提示密码不正确
用户注册测试-边界值 进入用户注册页面 输入两次密码不同,其他信息规范 提示注册失败 提示两次密码不同

续表 6-1

功能模块 前置条件 测试步骤 预期结果 实测结果
用户注册测试-边界值 进入用户注册页面 输入电话不规范,其他信息规范 提示注册失败 提示电话不正确
用户注册测试-边界值 进入用户注册页面 输入邮箱不规范,其他信息规范 提示注册失败 提示邮箱格式不正确
用户注册测试-集成测试 进入用户注册页面,IP与端口可用 填写用户名存在,其他信息填写正确 提示注册失败 提示用户已存在
用户注册测试-集成测试 进入用户注册页面,IP与端口可用 填写注册均信息规范且用户名不存在 提示注册成功,跳转登录界面 提示注册成功,跳转登录界面
用户登录测试-必填项 用户已经注册并激活账户 用户名为空,密码规范,点击登录 提示用户名为空 提示用户名为空
用户登录测试-必填项 用户已经注册并激活账户 密码为空,用户名规范,点击登录 提示密码为空 提示密码为空
用户登录测试-边界值 用户已经注册并激活账户 用户名规范,密码不规范,点击登录 登陆失败 登陆失败
用户登录测试-边界值 用户已经注册并激活账户 密码规范,用户名不规范,点击登录 登陆失败 登陆失败
用户登录测试-边界值 用户已经注册并激活账户 密码与用户名均不规范,点击登录 登陆失败 登陆失败
用户登录测试-集成测试 用户已经注册账户 用户名和密码输入正确,点击登录 登录成功,跳转至我的文件界面 登录成功,跳转至我的文件界面
用户登录测试-缓存测试 用户已经注册账户 选择记住密码登录,再进登录界面 登录栏有上次用户输入的信息 登录栏有上次用户输入的信息
文件上传测试-文件类型 1.用户已登录,并进入文件页面;2.准备1个非图像文件 1.选择非图像文件文件;2.确认上传 提示上传成功,文件信息保存至数据库中 提示上传成功,文件信息保存至数据库中
文件上传测试-文件类型 1.用户已登录,并进入文件页面;2.准备1个图像文件 1.选择图像文件;2.确认上传 提示上传成功,文件信息保存至数据库中 提示上传成功,文件信息保存至数据库中
文件上传测试-性能测试 1.用户已登录,并进入文件页面;2.准备10个文件 1.选择准备好的文件;2.确认上传 10个文件加入到上传队列 10个文件加入到上传队列

续表 6-1

功能模块 前置条件 测试步骤 预期结果 实测结果
文件上传测试-性能测试 用户已登录,并进入文件页面 1.选择1KB文件;2.确认上传 成功上传 成功上传
文件上传测试-性能测试 用户已登录,并进入文件页面 选择准备的100MB文件;确认上传 成功上传 成功上传
文件秒传测试-性能测试 1.用户已登录,并进入文件页面;2.准备已上传过的文件 1.选择准备好的文件;2.确认上传 直接提示上传成功,文件信息保存至数据库中 直接提示上传成功,文件信息保存至数据库中
文件下载测试 1.用户已经登陆;2.已经有上传好的文件 1.选择一个自己文件点击下载;2.在本地打开文件 文件成功打开,且格式正确 文件成功打开,且格式正确
文件下载测试-共享文件 1.用户已经登陆;2.系统中有共享文件存在 在共享文件界面点击一个文件下载,然后打开下载文件 文件成功打开,且格式正确 文件成功打开,且格式正确
文件下载测试-共享文件 1.用户已经登陆;3.系统中有共享文件存在 在共享文件界面点击一个文件下载,然后再上传该文件 文件采用秒传方式上传成功 文件采用秒传方式上传成功
文件共享测试 1.用户已经登陆;2.文件列表存在文件 用户选择文件设为共享并进共享页面 用户1可以查找到该文件 用户1可以查找到该文件
文件共享测试 1.准备两个用户,且已经登陆;2.文件列表存在文件 1.用户1选择一个文件共享;2.用户2转存该文件 用户2可以在共享界面转存该文件 用户2可以在共享界面转存该文件
文件共享测试 1.准备两个用户,且已经登陆;2.文件列表存在文件 1.用户1选择一个文件共享;2.用户2取消共享该文件 用户2不可以在共享界面取消共享该文件 用户2不可以在共享界面取消共享该文件
文件共享测试 1.准备两个用户,且已经登陆;2.文件列表存在文件 1.用户1选择文件取消共享;2.用户2前往共享页面 用户2不可以找到该文件 用户2不可以找到该文件
文件共享测试 1.用户已经登陆;2.文件列表存在文件 用户将转存文件共享 用户不可以共享该文件 用户不可以共享该文件
文件列表测试-我的文件 1.用户已经登录;2.该存在文件 进入我的文件 图标形式显示用户所有文件 图标形式显示用户所有文件

续表 6-1

功能模块 前置条件 测试步骤 预期结果 实测结果
文件列表测试-共享文件 1.用户已经登录;2.存在共享文件 进入共享文件 图标形式显示所有共享文件 图标形式显示所有共享文件
文件列表测试-下载榜 1.用户已经登录;2.存在共享文件 进入下载榜 以下载量排序共享文件信息 以下载量排序共享文件信息
文件删除测试-删除普通文件 1.用户已经登录;2.系统中存在文件 1.用户选择一个文件删除 用户文件列表中没有该文件 用户文件列表中没有该文件
文件删除测试-删除共享文件 1.准备两个用户,且已经登录;2.系统中存在文件 1.用户1删除自己的共享文件;2.用户2进入共享页面 用户2不可以找到该文件 用户2不可以找到该文件
文件删除测试-删除共享文件 1.用户已经登录;2.系统中存在文件 用户选择非自己的共享文件点击删除 删除失败 删除失败
文件删除测试-删除共享文件 用户1用户2均拥有该共享文件,且用户1为共享者 1.用户1删除该文件2.用户2进入共享文件界面查找 用户2不可以查找到该文件 用户2不可以查找到该文件
文件删除测试-删除共享文件 用户1用户2均拥有该共享文件,且用户2为共享者 1.用户1删除该文件2.用户2进入共享文件界面查找 用户2可以查找到该文件 用户2可以查找到该文件
图像预览测试 用户拥有已上传非图像文件 选中非图像文件右键点击预览 提示该文件非图像,无法预览 提示该文件非图像,无法预览
图像预览测试 用户拥有已上传图像文件并点击预览 选中图像文件右键点击预览 显示预览效果 显示预览效果
图像预览测试-缩略图 进入文件列表界面,缓存没有预览图 先显示默认图像,一段时间后部分图像逐渐显现缩略图 先显示默认图像,一段时间后部分图像逐渐显现缩略图
图像预览测试-缩略图 进入文件列表界面,缓存有预览图 显示图像缩略图 显示图像缩略图
图像预览测试-缩略图 进入文件列表界面 1.预览图像文件2.刷新文件列表 预览过的图像文件显示图像缩略图 预览过的图像文件显示图像缩略图
图像预览测试-缓存 进入文件列表界面 右键取消缓存,刷新界面 未在缓存中的缩略图不会自动加载 未在缓存中的缩略图不会自动加载
图像预览测试-缓存 进入文件列表界面 右键点击清理缓存 缓存文件清空 缓存文件清空
用户切换测试 进入文件界面 点击切换用户 切换到登录界面 切换到登录界面

6.4.2 性能测试结果

在性能测试中主要通过SpeedTest性能测试工具监控指定进程,通过上传或下载指定大小的数据来测试上传与下载过程中数据接收的速度。在文件上传或下载的速度测试过程中以采样时间段速度的形式进行平均速度的计算。以下是采样测试结果。

img

图6-2 虚拟机服务端环境性能测试

img

图6-3 阿里云服务端环境性能测试

7 总结

作为大学四年知识汇聚的结晶,基于云存储的图像管理平台的设计与实现最终顺利完成。该平台尽管采用C++设计,但所包含的技术点却很多。

首先服务端的架构就包含分布式文件系统、持久化数据库、非关系型数据库、负载均衡等比较新但应用很广的技术,这些技术原本只能通过书籍或课堂接触,而通过本平台的设计均得到了实践,因此对今后应用的开发有着启迪性的作用;同时,对于目前服务端主流的分布式文件系统、Redis、MySQL、Nginx等应用较广的技术的使用越来越熟练。由于服务端部署在Linux操作系统上,同时用到很多云计算相关技术,为之后无论是应用开发还是大数据开发均提供了宝贵的经验。

客户端通过Qt设计,而Qt作为C++跨平台界面开发的工具,里面支持包括Lambda表达式等一系列C++11特性,同时包含很多通过C++实现的比较新的技术。在设计客户端的同时,不仅巩固了C++基础,同时也为客户端相关的开发积累了丰富的经验。

刚开始设计该平台时,我还没有多少项目开发经验,但由于该应用的功能正好用处很广,不仅可以用来作为文件存储的云盘,同时还可以作为图床供博客使用,因此满怀兴趣的我开始查阅云存储相关的资料。在学习的过程中,不仅掌握了目前时代较前沿的技术,同时也拓展了视野,认识到纸上得来终觉浅,作为开发者不仅需要不断学习,更重要的是进行实践,有了足够的设计经验,对于新的技术学起来会非常快,这样才能跟随时代发展而不被时代所甩掉。

该平台作为较完整的项目,我将会通过GitHub将该平台开源化,供其他开发者使用的同时进行学习与交流,为开源软件贡献一份尽管微不足道但充满诚意的力量。

致 谢

首先,我要感谢我的指导老师——齐勇老师。此次基于云存储的图像管理平台设计与实现以及毕业论文的撰写与完善均是在齐勇老师的耐心辅导下完成的,从毕业设计开题到毕业论文的完善,齐老师都定期查看,悉心辅导,同时推荐了许多有用的材料,给予我很多有价值的建议。尽管由于一系列不可控因素的存在,导致此次毕业设计齐老师只能通过线上的方式指导,但齐老师那对于学术的严谨态度、对于项目的精益求精品质都使我受益匪浅。正因为齐老师这种认真负责的责任感以及对学生细致入微的关爱,让我一次次在面对压力与困难时从未妥协,也正因为有齐老师的指导我才可以顺顺利利地完成这次毕业设计。

其次,我还要感谢和同一毕业小组的同学们,在完成毕业设计的时光里我们互相勉励,一起解决了毕业设计中的一个个问题,一起进步与成长。纵使日后各奔东西,曾经的这份共情仍在。

在我们即将踏出校门步入社会之际,我的思绪万千,曾几何时懵懵懂懂地踏入大学校门,连最基本的编程都还没学,而现在已经能够独立自主设计一个完整的项目,这背后不仅包含自身的努力与付出,更映射着学校的栽培、老师的关爱、辅导员的呵护以及同学们的互助。因此我向你们致以我最真挚的感激,感谢一路有你们伴我度过这段有欢笑、有快乐、有付出、有收获的大学时光。

参 考 文 献

[1] 张雨, 蔡鑫, 李爱民, 等. 分布式文件系统与 MPP 数据库的混搭架构在电信大数据平台中的应用[J]. 电信科学, 2013, 29(11): 12-16.

[2] 王波. 基于FastDFS的轻量级分布式文件系统的设计与实现[D]. 东北大学,2013.

[3] 巨头的云计算,谁将是下一个霸主?[J]. 软件, 2018, 39(06): 224-227.

[4] 杨正洪. 智慧城市: 大数据, 物联网和云计算之应用[M]. 清华大学出版社, 2017.

[5] 陈肇雄. 推进工业和信息化高质量发展[J]. 网信军民融合,2019(07):5-7.

[6] 徐为成. 5G时代 云计算发展的五大新趋势[J]. 通信世界,2019(20):46.

[7] Li S, Da Xu L, Zhao S. 5G Internet of Things: A survey[J]. Journal of Industrial Information Integration, 2018, 10: 1-9.

[8] 本刊讯. 工信部印发《云计算发展三年行动计划(2017-2019年)》[J]. 中国公共安全, 2017(05): 20.

[9] Singh J. Study on challenges, opportunities and predictions in cloud computing[J]. International Journal of Modern Education and Computer Science, 2017, 9(3): 17.

[10] Jiang C, Wang Y, Ou D, et al. Energy efficiency comparison of hypervisors[J]. Sustainable Computing: Informatics and Systems, 2019, 22: 311-321.

[11] Mesran M, Abdullah D, Hartama D, et al. Combination Base64 and Hashing Variable Length for Securing Data[C]//Journal of Physics: Conference Series. 2018, 1028: 012056.

[12] 刘佳祎,崔建明,智春. 基于Nginx服务器的动态负载均衡策略研究[J/OL]. 桂林理工大学学报:1-11[2020-06-22].

[13] Hallberg J. Memcached och Redis cachning på lokalt system i en dator[J]. 2019.

[14] 张兰. 基于云计算的电子商务数据缓存处理的研究[J]. 电脑知识与技术,2016,12(23):249-250.

[15] 余庆. 分布式文件系统 FastDFS 架构剖析[J]. 程序员, 2010 (11): 63-65.

[16] 阮光耀. 基于负载均衡的FastDFS新存储节点的同步任务分配策略研究[D]. 武汉纺织大学,2019.

[17] 赵晔. 基于Nginx的Web后端服务器集群负载均衡技术的研究与改进[D]. 昆明理工大学,2017.

[18] Chen X, Song Y, Ye H, et al. Research and Implementation of Digital Ancient Book Library Based on Solr/Lucene[J]. 2018.

[19] 许红军. 灵活配置,强化Nginx安全管理[J]. 网络安全和信息化,2018(06):132-135.

[20] Eng L Z. Qt5 C++ GUI programming cookbook[M]. Packt Publishing Ltd, 2016.

[21] Pospelov G. Developing BornAgain graphical user interface: lessons learned[C]//Workshop on Neutron Scattering Data Analysis Software. 2018, 6: 8.

[22] 陶文玲,侯冬青. PyQt5与Qt设计师在GUI开发中的应用[J]. 湖南邮电职业技术学院学报,2020,19(01):19-21.

[23] 李飞. 基于C/S模式的图件管理系统的构建[J]. 科技视界,2019(27):39-41.

[24] 石珊. 云平台下基于FastDFS的文件管理系统的研究与实现[D]. 电子科技大学,2019.

[25] Bhandari A, Bhuiyan M, Prasad P W C. Enhancement of MD5 Algorithm for Secured Web Development[J]. JSW, 2017, 12(4): 240-252.

[26] Carlson J L. Redis in action[M]. Manning Publications Co., 2013.

[27] 张云, 许江淳, 李玉惠, 等. 基于 Nginx 服务器负载均衡技术的研究与改进[J]. 软件, 2017, 38(8): 6-12.

[28] 王宁. 基于分布式云平台视频存储及管理[D]. 中国石油大学(华东),2016.

[29] 孔德云. 基于FastDFS的大并发问题的研究与应用[D]. 中北大学,2017.

[30] Bourhis P, Reutter J L, Suárez F, et al. JSON: data model, query languages and schema specification[C]//Proceedings of the 36th ACM SIGMOD-SIGACT-SIGAI symposium on principles of database systems. 2017: 123-135.

[31] 杨丽波. 浅析集成测试和系统测试的关系[J]. 电子测试,2017(20):109-110.

[32] 范方政. 软件测试技术与缺陷跟踪管理的应用研究[D]. 吉林大学,2014.

[33] 朱健. 基于Qt Test的自动化单元测试[J]. 价值工程,2017,36(14):216-219.

附 录

图3-1 FastDFS分布式文件系统结构 7

图3-2 FastDFS分布式文件系统集群 8

图3-3 反向代理服务器原理 9

图4-1 总体设计框架 12

图4-2 总体方案结构 13

图4-3 用户注册流程图 15

图4-4 用户登录流程图 16

图4-5 文件列表查询流程图 16

图4-6 数据秒传流程图 17

图4-7 数据上传流程图 18

图4-8 文件删除流程图 19

图4-9 文件共享流程图 20

图4-10 文件下载流程图 21

图4-11 图像预览流程图 21

图4-12 客户端总体流程图 23

图4-13 服务端总体流程图 24

图5-1 数据库表结构 26

图 5-2 用户界面结构 29

图5-3 登录界面效果图 31

图5-4 注册界面效果图 31

图5-5 文件界面结构 32

图5-6 文件界面导航栏 33

图5-7 我的文件效果图 34

图5-8 共享列表效果图 34

图5-9 下载榜效果图 35

图5-10 传输列表效果图 35

图5-11 配置设置效果图 37

图5-12 任务进度图 38

图5-13 上传任务界面效果图 38

图5-14 图像预览列表图 45

图6-1 GUI单元测试部分结果 48

图6-2 虚拟机服务端环境性能测试 52

图6-3 阿里云服务端环境性能测试 52


文章结束了,但我们的故事还在继续
坚持原创技术分享,您的支持将鼓励我继续创作!