Qt实现基于多线程的文件传输(服务端,客户端)
Qt实现基于多线程的文件传输(服务端,客户端)
1. 效果
先看看效果图
这是传输文件完成的界面
客户端
服务端
2. 知识准备
其实文件传输和聊天室十分相似,只不过一个传输的是文字,一个传输的是文件,而这方面的知识,我已经在前面的博客写过了,不了解的同学可以去看一下
C++网络编程
Qt实现网络聊天室(客户端,服务端)
还有多线程相关的知识
Qt中的多线程与线程池浅析+实例
2.1 关于多线程
这次是用多线程实现的文件传输系统,其中对客户端来说,子线程负责连接服务器,发送文件,主线程负责修改进度条,对服务端来说,也是用子线程来处理客户端的请求
2.2 关于文件传输
文件传输采用的是,对客户端,首先是发送出整个文件的大小,需要用到QFileInfo这个类,然后再发送文件
对服务端,先接收文件的大小,然后判断,当接收的文件大小等于第一次接收的文件大小时,停止接收,断开连接
3. 源代码
我在代码里面都有非常详细的注释,所以就直接放上代码啦
3.1 客户端
头文件 mainwindow.h
#ifndef MAINWINDOW_H#define MAINWINDOW_H#include <QMainWindow>QT_BEGIN_NAMESPACEnamespace Ui { class MainWindow; } QT_END_NAMESPACEclass MainWindow : public QMainWindow { Q_OBJECTpublic: 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 <QMessageBox>#include <QThread>#include "sendfile.h"#include <QFileDialog>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 <QObject>#include <QTcpSocket>class SendFile : public QObject { Q_OBJECTpublic: 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 <QFile>#include <QHostAddress>#include <QFileInfo>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 <QMainWindow>#include <QTcpServer>QT_BEGIN_NAMESPACEnamespace Ui { class MainWindow; } QT_END_NAMESPACEclass MainWindow : public QMainWindow { Q_OBJECTpublic: 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 <QMessageBox>#include <QTcpSocket>#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 <QThread>#include <QTcpSocket>class RecvFile : public QThread { Q_OBJECTpublic: 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 <QFile>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(); }
3.4 文件目录
4. 结束语
如果有些小伙伴需要工程文件等,可以联系我
来源https://www.cnblogs.com/wanghongyang/p/14926303.html