目录
一、项目介绍
1、项目描述
随着时代的发展,业务数据量的剧增及移动办公需求,人们对内存的需求越来越强,传统的存储产品,在容量及携带型方面还需要得到提升,因此,网盘应运而生。
该网盘是能够提供文件同步,备份及共享等服务的网络云存储平台。可以随时随地的把照片、音乐、视频、文档等轻松的保存到网盘,无须担心文件丢失。通过网盘,用户可以多终端上传和下载、管理、分享文件(聊天)。该项目是模仿百度云网盘而产生的项目。
项目描述示意图
用户可以随时随地地上传下载、编辑和分享文件
搜索好友、加好友、好友聊天
2、项目组成模块
采用C/S架构,数据库存储用户信息,磁盘存储用户文件
3、项目技术要点
3.1、多线程:
客户端:可以同时上传多个数据,在发送和接收信息聊天的时候是同时进行的,接收数据和发送数据是并发的。
服务器:可以同时处理所有客户端的请求。,服务器存放数据的时候也是可以多线程的
3.2、TCP Socket网络编程
客户端和服务器的连接,是通过网络连接起来的,数据传输方式TCP,比较可靠。
3.3、SQLite3数据库
存放用户信息,好友、密码
3.4、面向对象编程
着重掌握的,使用C++创建对象
二、用户功能测试
1、查看在线用户测试
客户端发送查看请求(只发送用户的名字),服务器将数据库中在线的用户查询出来并发送给客户端,客户端接收在线用户信息并作显示。
1.1、运行服务器
没登陆之前数据库的online的字段都是0
1.2、登录两个账号
1.3、点击显示在线用户,可以看到jack和lucy
2、搜索用户测试
客户端发送查看请求(发送用户的名字,在线状态),服务器将数据库中在线用户查询出来并发送给客户端,客户端接收用户信息并显示。
void Friend::searchUser()
{
//搜索用户的时候,会弹出一个对话框来
QString name = QInputDialog::getText(this, "搜索", "用户名:");
//将名字打印出来
if(!name.isEmpty()){
qDebug()<<name;
PDU *pdu =mkPDU(0);
memcpy(pdu->caData, name.toStdString().c_str(),name.size());
pdu->uiMsgType = ENUM_MSG_TYPE_SEARCH_USER_REQUEST;
TcpClient::getinstance().getTcpSocket().write((char*)pdu, pdu->uiPDULen);
free(pdu);
pdu = NULL;
}
}
2.1、打开服务器,登录两个账号jack,lucy
2.2、在lucy界面查找jack,提示jack 在线
2.3、找数据库里面的rose
2.4、查询数据库没有的dandanfan
3、添加好友
4、删除好友测试
A、客户端A发送删除好友(发送的信息包括双方的用户名)
B、服务器将数据库中好友信息删除,并发送删除信息给客户端A、B
C、客户端B接收信息并显示
bool OperateDB::handleDeleteFriend(const char *name, const char *friendname)
{
if(NULL==name||NULL==friendname)
{
return false;
}
QString data = QString("delete from friend where id=(select id from usrInfo where name=\'%1\') "
"and friendId=(select id from usrInfo where name=\'%2\')").arg(name).arg(friendname);
//qDebug()<<data;
QSqlQuery query;
query.exec(data);
data = QString("delete from friend where id=(select id from usrInfo where name=\'%1\') "
"and friendId=(select id from usrInfo where name=\'%2\')").arg(friendname).arg(name);
//qDebug()<<data;
query.exec(data);
return true;
}
5、私聊测试
A、客户端A发送私聊信息请求(发送的信息包括双方的用户名,聊天信息)
B、如果双方在线则直接转发给B,不在线则回复私聊失败,对方不在线
C、客户端B接收信息并显示
case ENUM_MSG_TYPE_PRIVATE_CHAT_REQUEST:
{
if(PrivateChat::getInstance().isHidden())
{
PrivateChat::getInstance().show();
}
char caSendName[32]={'\0'};
memcpy(caSendName,pdu->caData,32);
QString strSendName = caSendName;
PrivateChat::getInstance().setChatName(strSendName);
PrivateChat::getInstance().updateMsg(pdu);
break;
}
6、群聊测试
A、客户端A发送群聊信息请求(发送的信息包括用户名,聊天信息)
B、服务器转发给所有在线的好友
C、好友接收信息并显示
case ENUM_MSG_TYPE_GROUP_CHAT_REQUEST:
{
char caName[32] ={'\0'};
strncpy(caName, pdu->caData, 32);
//那些好友在线
QStringList onlineFriend = OperateDB::getInstance().handleFlushFriend(caName);
QString tmp;
//转发
for(int i=0;i<onlineFriend.size();i++)
{
tmp=onlineFriend.at(i);
MyTcpServer::getInstance().reSend(tmp.toStdString().c_str(),pdu);
}
break;
}
三、文件功能测试
1、创建文件夹测试
A、当我们注册新用户时,服务器需要用用户名创建一个文件夹,后续该客户端所有的文件都放在以该客户端的用户名的那个文件夹下面。
B、注册之后,还需要创建文件夹,在文件夹下面再创建文件夹...(可以包含多个子文件夹),这个时候就需要发送用户名用户信息以及新建的文件名发送给服务器。在这里用户名的作用就是服务器根据这个用户名找到应该操作那个文件夹,才是该客户端的文件夹,还有就是创建的新的文件是在那个子文件夹下面。
C、服务器收到请求之后,在服务器端创建新的文件夹,将反馈信息给客户端。反馈信息基本就是两种:创建成功和创建不成功。那么创建失败的原因是有两种:第一种就是这个文件已经存在了,第二种就是系统出现了问题。
D、客户端收到反馈信息之后,将信息显示出来。这样就知道自己是创建成功了还是失败了。
2、查看文件测试
A、首先客户端发送查看请求(包含目录信息)
B、服务器将文件名字还有文件的类型发送给客户端(只发送文件的名字)
C、客户端接收回复信息后,在文件列表里面显示
void Book::updateFileList(const PDU *pdu)
{
if(NULL==pdu)
{
return;
}
FileInfo *pFileInfo =NULL;
int iCount = pdu->uiMsgLen/sizeof (FileInfo);
for(int i=0 ;i<iCount;i++)
{
pFileInfo =(FileInfo*)(pdu->caMsg)+i;
qDebug()<<pFileInfo->caFileName<<pFileInfo->iFileType;
QListWidgetItem *pItem = new QListWidgetItem;
if(0==pFileInfo->iFileType)
{
pItem->setIcon(QIcon(QPixmap(":/map/dir.jpg")));
}
else if(1==pFileInfo->iFileType) {
pItem->setIcon(QIcon(QPixmap(":/map/reg.png")));
}
pItem->setText(pFileInfo->caFileName);
m_pBookListW->addItem(pItem);
}
}
3、删除文件夹
A、客户端发送删除请求(包含目录信息和要删除的文件名)
目录信息:目录中还有子目录,子目录中还有子目录,必须将目录信息发送给服务器,这样服务器才知道在那个文件夹下面删除文件
B、服务器接收请求,在指定的文件夹下面,删除指定的文件,并发送回复信息给客户端。(成功失败)
C、客户端接收回复信息并显示。(成功与否)
3.1、删除常规文件
3.2、删除文件夹
3.3、刷新文件夹
4、文件重命名
A、客户端发送重命名请求(包含目录信息,要修改的文件名以及新文件名)
B、服务器收到请求之后,根据该请求中的目录信息以及新旧文件名字,对文件进行重命名,并回复到客户端
C、客户端收到回复信息之后,对该信息进行显示,通知用户重命名成功或者失败
5、进入文件夹测试
A、客户端发送进入文件夹的请求(该请求包含目录信息以及要进入的文件夹名字)
B、服务器收到该请求之后,服务器首先判断路径是否正确。
正确:则进入到该路径中,将新文件夹中的文件信息发送给客户端
不正确:回复失败给客户端
C、客户端接收来自服务器的回复信息并显示
5.1、进入常规文件
5.2、进入文件夹
6、返回上一级测试
A、客户端返回上一级功能的时候,我们首先检查是否是在根目录,如果在根目录则直接返回失败,反之则返回上一级。
B、假如是在某个子目录里面,客户端发送返回上一级请求(包含上一级目录信息,原因是获得上一级的文件信息)
C、服务器收到请求之后,将上一级目录中的文件名发送给客户端,这块就和刷新是一样的
D、客户端接收回复信息并显示
点击jack文件夹,里面的文件有三个,之后点击返回按钮,直接返回到jack部分。再点击一次返回,因为已经是根目录了,所以直接警告
7、上传文件
A、客户端发送上传文件请求,请求包括:包括当前路径,上传文件名,上传文件内容
包括当前路径,上传文件名,这个时候不上传文件内容,当服务器接收到上传请求之后,在指定的路径下面,将该文件创建出来,客户端发送上传请求之后,上传文件内容。
B、服务器接收到客户端文件内容,将信息保存到之前创建的文件中,在服务器接受完上传的内容之后,服务器发送信息给客户端
C、客户端接受回复信息并显示
7.1、点击上传文件,选择文件并打开
发现jack文件夹里面也有了makefile文件
7.2、上传大的文件
8、删除常规文件
A、客户端发送删除请求(包含目录信息和要删除的文件名)
B、服务器接收请求之后,将请求中的目录及文件名提取出来,删除指定的文件,并将删除结果发送回复给客户端
C、客户端接收到回复信息之后,进行显示
8.1、删除常规文件
8.2、删除目录
9、下载文件
A、客户端发送下载请求(请求包含路径,下载文件名)
B、服务器提取指定内容以及文件大小发送给客户端
C、客户端循环接收服务器发送过来的文件内容,保存到文件中(客户端需要指定一个位置来保存我们接收到的文件内容,QFileDialog)
9.1、点击需要下载的文件
9.2、选择保存路径
在桌面查看是否下载成功
10、分享文件
A、客户端发送分享文件请求(请求包含分享者、接收者、当前路径以及文件名)
那么PDU应该如何设置呢?分享者放在cadata里面,接收者放在camsg里面,当前路径也是camsg,那都放在一起了,如何做区分呢?将分享者和接收者的个数放在cadata里面,文件名也放在camsg或者将当前路径和文件名拼接,一起放在msg里面。
B、服务器端接收请求,对请求进行操作,并将操作结果返回给客户端
C、客户端接收回复信息并显示
10.1、常规文件分享测试
登录jack和lucy这两个好友,刷新jack的文件,将test.txt文件发送给lucy,弹出窗口提示之后,刷新lucy文件,发现分享文件成功
10.2、文件夹分享测试
A、用户登录,刷新好友
B、点击图书,刷新文件,共享文件,选择lucy好友
C、点击yes
D、刷新lucy的文件
E、查看文件是否真正分享完成
11、移动文件
A、客户端发送移动文件请求(请求包含当前目录,目标目录)
B、服务器接收请求之后,根据请求中指定的目录和目标目录进行移动,移动完成之后,回复客户端
C、客户端接收到回复信息之后,进行显示
11.1、选择要移动的文件
打开图书,选择要移动的文件,先点击常规文件,点击移动文件按钮,目标目录按钮变亮,可以点击。
11.2、移动到常规文件
点击目标目录,报错。因为是常规文件
11.3、将文件移动到aaa里面
刚开始test.txt在jack文件夹下
现在在aaa下面
四、登录注册测试
1、注册测试
1.1、运行TcpServer
1.2、运行TcpClient
1.3、再注册一次tony,就会提示
1.4、查看cloud.db数据库里面是否有数据
2、登录测试
2.1、运行TcpServer
2.2、运行TcpClient
输入以下信息
2.3、再登录一次jack,就会提示