当前位置:   article > 正文

QT多线程实现基于TCP的文件传输功能_qt ftp多线程文件传输

qt ftp多线程文件传输

写在前面

QT中多线程的两种使用方式:

1、继承QThread类并重写run()函数。

2、使用moveToThread()函数将QObject派生类移动到新的线程中执行。

客户端

客户端UI

客户端主窗口头文件:

  1. #ifndef SENDFILEWINDOW_H
  2. #define SENDFILEWINDOW_H
  3. #include <QMainWindow>
  4. #include <QThread>
  5. namespace Ui {
  6. class SendFileWindow;
  7. }
  8. class SendFileWindow : public QMainWindow
  9. {
  10. Q_OBJECT
  11. public:
  12. explicit SendFileWindow(QWidget *parent = nullptr);
  13. ~SendFileWindow();
  14. private slots:
  15. //连接服务器
  16. void on_connectBtn_clicked();
  17. //选择文件
  18. void on_SelectFilelBtn_clicked();
  19. //发送文件
  20. void on_sendFileBtn_clicked();
  21. signals:
  22. //主函数开始连接服务器信号
  23. void StartConnect(QString ip, unsigned short port);
  24. //主线程发送文件信号
  25. void sendFileSignal(QString filename);
  26. private:
  27. Ui::SendFileWindow *ui;
  28. };
  29. #endif // SENDFILEWINDOW_H

实现:

  1. #include "sendfilewindow.h"
  2. #include "sendfile.h"
  3. #include "ui_sendfilewindow.h"
  4. #include <QMessageBox>
  5. #include <QFileDialog>
  6. SendFileWindow::SendFileWindow(QWidget *parent) :
  7. QMainWindow(parent),
  8. ui(new Ui::SendFileWindow)
  9. {
  10. ui->setupUi(this);
  11. setWindowTitle("发送文件窗口");
  12. ui->IPlineEdit->setText("127.0.0.1");
  13. ui->portlineEdit->setText("8080");
  14. ui->progressBar->setRange(0,100);
  15. ui->progressBar->setValue(0);
  16. //线程对象
  17. QThread * myThread = new QThread;
  18. //任务对象
  19. SendFile *task = new SendFile;
  20. task->moveToThread(myThread); //将任务加入线程
  21. //主线程发出连接服务器的信号,子线程执行连接服务操作
  22. connect(this, &SendFileWindow::StartConnect, task, &SendFile::connectServer);
  23. connect(this, &SendFileWindow::sendFileSignal, task, &SendFile::sendFile);
  24. //处理子线程发送的信号
  25. connect(task, &SendFile::connectSuccessfully, this, [=](){
  26. QMessageBox::information(this, "提示","成功连接服务器");
  27. });
  28. connect(task, &SendFile::connectDestroyed, this,[=](){
  29. myThread->quit();
  30. myThread->wait();
  31. task->deleteLater();
  32. myThread->deleteLater();
  33. });
  34. connect(task, &SendFile::GetProgressValue, this->ui->progressBar, &QProgressBar::setValue);
  35. myThread->start();
  36. }
  37. SendFileWindow::~SendFileWindow()
  38. {
  39. delete ui;
  40. }
  41. void SendFileWindow::on_connectBtn_clicked()
  42. {
  43. //点击连接服务器按钮后,主线程发送开始连接服务器的信号
  44. QString ip = this->ui->IPlineEdit->text();
  45. unsigned short port = this->ui->portlineEdit->text().toUShort();
  46. emit StartConnect(ip, port);
  47. }
  48. void SendFileWindow::on_SelectFilelBtn_clicked()
  49. {
  50. QString filename = QFileDialog::getOpenFileName();
  51. this->ui->filepath->setText(filename);
  52. }
  53. void SendFileWindow::on_sendFileBtn_clicked()
  54. {
  55. QString filename = this->ui->filepath->text();
  56. emit sendFileSignal(filename);
  57. }

子线程负责连接数据库和发送文件

子线程头文件:(应该说是子任务类,不属于线程,只是将子任务加入了子线程中)

  1. #ifndef SENDFILE_H
  2. #define SENDFILE_H
  3. #include <QObject>
  4. #include <QTcpSocket>
  5. class SendFile : public QObject
  6. {
  7. Q_OBJECT
  8. public:
  9. explicit SendFile(QObject *parent = nullptr);
  10. //连接服务器
  11. void connectServer(QString ip, unsigned short port);
  12. //发送文件
  13. void sendFile(QString filePath);
  14. private:
  15. QTcpSocket *m_socket;
  16. signals:
  17. //成功连接服务器的信号
  18. void connectSuccessfully();
  19. //断开服务器连接信号
  20. void connectDestroyed();
  21. //发送进度
  22. int GetProgressValue(int value);
  23. };
  24. #endif // SENDFILE_H

任务实现:

  1. #include "sendfile.h"
  2. #include <QFile>
  3. #include <QFileInfo>
  4. #include <QHostAddress>
  5. SendFile::SendFile(QObject *parent)
  6. : QObject{parent}
  7. {
  8. }
  9. void SendFile::connectServer( QString ip,unsigned short port)
  10. {
  11. m_socket=new QTcpSocket;
  12. m_socket->connectToHost(QHostAddress(ip),port);
  13. //QTcpSocket::connected该信号属于子线程,无法直接在主线程中调用
  14. //于是通过信号槽机制,定义一个SendFile的信号,将子线程的信号传递给主线程
  15. connect(m_socket, &QTcpSocket::connected, this, &SendFile::connectSuccessfully);
  16. connect(m_socket, &QTcpSocket::disconnected, this, [=](){
  17. m_socket->close();
  18. m_socket->deleteLater();
  19. emit connectDestroyed();
  20. });
  21. }
  22. void SendFile::sendFile(QString filePath)
  23. {
  24. QFile file(filePath);
  25. file.open(QFile::ReadOnly);
  26. QFileInfo fileinfo(filePath);
  27. int filesize = fileinfo.size();
  28. int curSize = 0;
  29. while (!file.atEnd()) {
  30. //在传输文件之前,第一次向套接字中写入文件大小,以便接收方可以知道需要接收多少数据
  31. if(curSize==0)
  32. {
  33. m_socket->write((char*) &filesize, 4); //用4个字节表示文件大小
  34. }
  35. QByteArray line = file.readLine();
  36. m_socket->write(line); //向套接字中写入数据
  37. curSize+=line.size();
  38. int progressValue = (curSize/filesize)*100; //进度值
  39. emit GetProgressValue(progressValue);
  40. }
  41. }

服务器端

服务器UI

服务器主窗口头文件:

  1. #ifndef RECEIVEWINDOW_H
  2. #define RECEIVEWINDOW_H
  3. #include <QMainWindow>
  4. #include <QTcpServer>
  5. #include <QTcpSocket>
  6. QT_BEGIN_NAMESPACE
  7. namespace Ui { class receiveWindow; }
  8. QT_END_NAMESPACE
  9. class receiveWindow : public QMainWindow
  10. {
  11. Q_OBJECT
  12. public:
  13. receiveWindow(QWidget *parent = nullptr);
  14. ~receiveWindow();
  15. signals:
  16. void newSocket(QTcpSocket *socket);
  17. private slots:
  18. //启动监听
  19. void on_PortpushButton_clicked();
  20. private:
  21. Ui::receiveWindow *ui;
  22. QTcpServer *m_server;
  23. };
  24. #endif // RECEIVEWINDOW_H

实现:

  1. #include "receivewindow.h"
  2. #include "ui_receivewindow.h"
  3. #include <QHostAddress>
  4. #include <QMessageBox>
  5. #include "receivefilethread.h"
  6. receiveWindow::receiveWindow(QWidget *parent)
  7. : QMainWindow(parent)
  8. , ui(new Ui::receiveWindow)
  9. {
  10. ui->setupUi(this);
  11. this->ui->PortlineEdit->setText("8080");
  12. m_server= new QTcpServer(this);
  13. connect(m_server, &QTcpServer::newConnection, this, [=](){
  14. QTcpSocket *socket = m_server->nextPendingConnection();
  15. //将在主线程生成的套接字对象传入接收文件的子线程中
  16. ReceiveFileThread *thread = new ReceiveFileThread;
  17. connect(this, &receiveWindow::newSocket, thread, &ReceiveFileThread::generateSocket);
  18. emit newSocket(socket);
  19. thread->start();
  20. //接受子线程接收完毕信号
  21. connect(thread, &ReceiveFileThread::receiveFinished, this, [=](){
  22. thread->quit();
  23. thread->wait();
  24. thread->deleteLater();
  25. socket->close();
  26. socket->deleteLater();
  27. QMessageBox::information(this,"提示","接收完毕");
  28. });
  29. });
  30. }
  31. receiveWindow::~receiveWindow()
  32. {
  33. delete ui;
  34. }
  35. void receiveWindow::on_PortpushButton_clicked()
  36. {
  37. unsigned short port = this->ui->PortlineEdit->text().toUShort();
  38. m_server->listen(QHostAddress::Any, port);
  39. QMessageBox::information(this, "提示","服务器已启动");
  40. }

服务器端用子线程接受文件。

子线程头文件:(重载run方法用于启动子线程)

  1. #ifndef RECEIVEFILETHREAD_H
  2. #define RECEIVEFILETHREAD_H
  3. #include <QObject>
  4. #include <QTcpSocket>
  5. #include <QThread>
  6. class ReceiveFileThread : public QThread
  7. {
  8. Q_OBJECT
  9. public:
  10. explicit ReceiveFileThread(QObject *parent = nullptr);
  11. void run() override;
  12. void generateSocket(QTcpSocket *socket);
  13. private:
  14. QTcpSocket *m_socket;
  15. signals:
  16. void receiveFinished();
  17. };
  18. #endif // RECEIVEFILETHREAD_H

子线程实现:

  1. #include "receivefilethread.h"
  2. #include <QFile>
  3. ReceiveFileThread::ReceiveFileThread(QObject *parent)
  4. : QThread{parent}
  5. {
  6. }
  7. void ReceiveFileThread::generateSocket(QTcpSocket *socket)
  8. {
  9. this->m_socket=socket;
  10. }
  11. void ReceiveFileThread::run()
  12. {
  13. //创建文件
  14. QFile *file= new QFile("receive.txt");
  15. file->open(QFile::WriteOnly);
  16. //写入文件
  17. int total=0;
  18. int count=0;
  19. QString name;
  20. connect(m_socket,&QTcpSocket::readyRead, this,[&](){
  21. //第一次接收的数据为文件大小
  22. if(count==0){
  23. m_socket->read((char *)&total,4);
  24. }
  25. if(count==4){
  26. name= m_socket->readAll();
  27. }
  28. QByteArray all = m_socket->readAll();
  29. count += all.size(); //总大小
  30. file->write(all);
  31. //判断数据是否接收完
  32. if(count==total)
  33. {
  34. m_socket->close();
  35. m_socket->deleteLater();
  36. file->close();
  37. file->deleteLater();
  38. emit receiveFinished(); //发出接收完毕信号给主线程
  39. }
  40. });
  41. //子线程进入循环,防止线程运行完了但是文件没有接收
  42. exec();
  43. }

本文内容由网友自发贡献,转载请注明出处:https://www.wpsshop.cn/w/weixin_40725706/article/detail/305116
推荐阅读
相关标签
  

闽ICP备14008679号