实现基于多线程的文件传输

源代码
我在代码里面都有非常详细的注释,所以就直接放上代码啦
1 客户端
头文件 mainwindow.h
ifndef MAINWINDOW_H define MAINWINDOW_H include QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE
class MainWindow : public QMainWindow
{

Q_OBJECT

public:
MainWindow(QWidget *parent = nullptr); ~MainWindow();

signals:
void startConnect(unsigned short,QString); // 发送文件信号 void sendFile(QString path);

private slots:
void on_connectServer_clicked(); void on_selFile_clicked(); void on_sendFile_clicked();

private:
Ui::MainWindow *ui;

};
endif // MAINWINDOW_H 源文件 mainwindow.cpp
include "mainwindow.h" include "ui_mainwindow.h" include include include "sendfile.h" include MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent) , ui(new Ui::MainWindow)

{
ui->setupUi(this); // 设置IP和端口 ui->ip->setText("127.0.0.1"); ui->port->setText("8989"); // 设置进度条 ui->progressBar->setRange(0,100); ui->progressBar->setValue(0); // 客户端在子线程中连接服务器 // 创建线程对象 QThread* t = new QThread; // 创建任务对象 SendFile* worker = new SendFile; // 将worker移动到子线程t中 worker->moveToThread(t); // 当发送sendFile信号,让worker的sendFile函数处理(子线程) connect(this,&MainWindow::sendFile,worker,&SendFile::sendFile); // 通过信号,让worker开始工作 // 因为worker 已经移动到了子线程中,因此connectServer这个槽函数是在子线程中执行的 connect(this,&MainWindow::startConnect,worker,&SendFile::connectServer); // 处理子线程发送的信号 // 连接成功 connect(worker,&SendFile::connectOK,this,[=](){ QMessageBox::information(this,"连接服务器","已经成功的连接了服务器,恭喜!"); }); // 断开连接 connect(worker,&SendFile::gameover,this,[=](){ // 资源释放 t->quit(); t->wait(); worker->deleteLater(); t->deleteLater(); }); connect(worker,&SendFile::curPercent,ui->progressBar,&QProgressBar::setValue); // 启动线程 t->start();

}
MainWindow::~MainWindow()
{
delete ui;

}
void MainWindow::on_connectServer_clicked()
{
QString ip = ui->ip->text(); unsigned short port = ui->port->text().toUShort(); emit startConnect(port,ip);

}
void MainWindow::on_selFile_clicked()
{
QString path = QFileDialog::getSaveFileName(); // 判断路径是否为空 if(path.isEmpty()) { QMessageBox::warning(this,"打开文件","选择的文件路径不能为空"); return; } ui->filePath->setText(path);

}
void MainWindow::on_sendFile_clicked()
{
// 发送文件信号 emit sendFile(ui->filePath->text());

}
头文件 Send File.h
ifndef SENDFILE_H define SENDFILE_H include include class SendFile : public QObject
{
Q_OBJECT

public:
explicit SendFile(QObject *parent = nullptr); // 连接服务器 void connectServer(unsigned short port,QString ip); // 发送文件 void sendFile(QString path);

signals:
// 通知主线程连接成功 void connectOK(); // 通知主线程连接成功 void gameover(); // 通知主线程发送文件进度百分比 void curPercent(int num);

private:
QTcpSocket* m_tcp;

};
endif // SENDFILE_H 源文件SendFile.cpp
include "sendfile.h" include include include SendFile::SendFile(QObject* parent) : QObject(parent)
{
}
void SendFile::connectServer(unsigned short port, QString ip)
{
m_tcp = new QTcpSocket; m_tcp->connectToHost(QHostAddress(ip),port); // 通知主线程连接成功 connect(m_tcp,&QTcpSocket::connected,this,&SendFile::connectOK); // 通知主线程断开连接 connect(m_tcp,&QTcpSocket::disconnected,this,[=](){ // 断开连接,释放资源 m_tcp->close(); m_tcp->deleteLater(); emit gameover(); });

}
void SendFile::sendFile(QString path)
{
QFile file(path); // 获取文件信息 QFileInfo info(path); int fileSize = info.size(); file.open(QFile::ReadOnly); // 一行一行的读文件 while(!file.atEnd()){ static int num = 0; // 为了让服务器端知道什么时候停止接收,所以得发送文件的大小 if(num ==0){ m_tcp->write((char*)&fileSize,4); }QByteArray line = file.readLine(); // 计算百分比,发给主线程 num +=line.size(); int percent =(num*100/fileSize); emit curPercent(percent); m_tcp->write(line); }

}
3.2 服务端
头文件mainwindow.h
ifndef MAINWINDOW_H define MAINWINDOW_H include include QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE
class MainWindow : public QMainWindow
{
Q_OBJECT

public:
MainWindow(QWidget *parent = nullptr); ~MainWindow();

private slots:
void on_setListen_clicked();

private:
Ui::MainWindow *ui; QTcpServer* m_s;

};
endif // MAINWINDOW_H 源文件maindow.cpp
include "mainwindow.h" include "ui_mainwindow.h" include include include "recvfile.h" MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent) , ui(new Ui::MainWindow)

{
ui->setupUi(this); m_s = new QTcpServer(this); connect(m_s,&QTcpServer::newConnection,this,[=](){ QTcpSocket* tcp = m_s->nextPendingConnection(); // 创建子线程,tcp通过参数传递 RecvFile* subThread = new RecvFile(tcp); subThread->start(); connect(subThread,&RecvFile::over,this,[=](){ subThread->exit(); subThread->wait(); subThread->deleteLater(); QMessageBox::information(this,"文件接受","文件接收完毕!!!"); }); });

}
MainWindow::~MainWindow()
{
delete ui;

}
void MainWindow::on_setListen_clicked()
{
unsigned short port = ui->port->text().toUShort(); m_s->listen(QHostAddress::Any,port);

}
头文件recvfile.h
ifndef RECVFILE_H define RECVFILE_H include include class RecvFile : public QThread
{
Q_OBJECT

public:
explicit RecvFile(QTcpSocket* tcp,QObject *parent = nullptr);

protected:
void run() override;

private:
QTcpSocket* m_tcp;

signals:
void over();

};
endif // RECVFILE_H 源文件recvfile.cpp
include "recvfile.h" include RecvFile::RecvFile(QTcpSocket tcp,QObject parent) : QThread(parent)
{
m_tcp = tcp;

}
void RecvFile::run()
{
QFile* file = new QFile("recv.txt"); file->open(QFile::WriteOnly); // 接收数据 connect(m_tcp,&QTcpSocket::readyRead,this,[=](){ static int count = 0; static int total = 0; if(count == 0){ m_tcp->read((char*)&total,4); } // 读出剩余数据 QByteArray all = m_tcp->readAll(); count += all.size(); file->write(all); if(count == total){ m_tcp->close(); m_tcp->deleteLater(); file->close(); file->deleteLater(); emit over(); } }); // 进入事件循环 exec();

【实现基于多线程的文件传输】}

    推荐阅读