赞
踩
QT中多线程的两种使用方式:
1、继承QThread类并重写run()函数。
2、使用moveToThread()函数将QObject派生类移动到新的线程中执行。
客户端UI
客户端主窗口头文件:
- #ifndef SENDFILEWINDOW_H
- #define SENDFILEWINDOW_H
-
- #include <QMainWindow>
- #include <QThread>
- namespace Ui {
- class SendFileWindow;
- }
-
- class SendFileWindow : public QMainWindow
- {
- Q_OBJECT
-
- public:
- explicit SendFileWindow(QWidget *parent = nullptr);
- ~SendFileWindow();
-
- private slots:
- //连接服务器
- void on_connectBtn_clicked();
- //选择文件
- void on_SelectFilelBtn_clicked();
- //发送文件
- void on_sendFileBtn_clicked();
-
- signals:
- //主函数开始连接服务器信号
- void StartConnect(QString ip, unsigned short port);
- //主线程发送文件信号
- void sendFileSignal(QString filename);
- private:
- Ui::SendFileWindow *ui;
- };
-
- #endif // SENDFILEWINDOW_H

实现:
- #include "sendfilewindow.h"
- #include "sendfile.h"
- #include "ui_sendfilewindow.h"
-
- #include <QMessageBox>
- #include <QFileDialog>
-
- SendFileWindow::SendFileWindow(QWidget *parent) :
- QMainWindow(parent),
- ui(new Ui::SendFileWindow)
- {
- ui->setupUi(this);
- setWindowTitle("发送文件窗口");
- ui->IPlineEdit->setText("127.0.0.1");
- ui->portlineEdit->setText("8080");
- ui->progressBar->setRange(0,100);
- ui->progressBar->setValue(0);
-
- //线程对象
- QThread * myThread = new QThread;
- //任务对象
- SendFile *task = new SendFile;
- task->moveToThread(myThread); //将任务加入线程
-
- //主线程发出连接服务器的信号,子线程执行连接服务操作
- connect(this, &SendFileWindow::StartConnect, task, &SendFile::connectServer);
- connect(this, &SendFileWindow::sendFileSignal, task, &SendFile::sendFile);
- //处理子线程发送的信号
- connect(task, &SendFile::connectSuccessfully, this, [=](){
- QMessageBox::information(this, "提示","成功连接服务器");
- });
- connect(task, &SendFile::connectDestroyed, this,[=](){
- myThread->quit();
- myThread->wait();
- task->deleteLater();
- myThread->deleteLater();
- });
-
- connect(task, &SendFile::GetProgressValue, this->ui->progressBar, &QProgressBar::setValue);
- myThread->start();
- }
-
- SendFileWindow::~SendFileWindow()
- {
- delete ui;
- }
-
- void SendFileWindow::on_connectBtn_clicked()
- {
- //点击连接服务器按钮后,主线程发送开始连接服务器的信号
- QString ip = this->ui->IPlineEdit->text();
- unsigned short port = this->ui->portlineEdit->text().toUShort();
- emit StartConnect(ip, port);
- }
-
-
- void SendFileWindow::on_SelectFilelBtn_clicked()
- {
- QString filename = QFileDialog::getOpenFileName();
- this->ui->filepath->setText(filename);
- }
-
-
- void SendFileWindow::on_sendFileBtn_clicked()
- {
- QString filename = this->ui->filepath->text();
- emit sendFileSignal(filename);
- }
-

子线程负责连接数据库和发送文件
子线程头文件:(应该说是子任务类,不属于线程,只是将子任务加入了子线程中)
-
- #ifndef SENDFILE_H
- #define SENDFILE_H
-
-
- #include <QObject>
- #include <QTcpSocket>
-
- class SendFile : public QObject
- {
- Q_OBJECT
- public:
- explicit SendFile(QObject *parent = nullptr);
- //连接服务器
- void connectServer(QString ip, unsigned short port);
- //发送文件
- void sendFile(QString filePath);
-
- private:
- QTcpSocket *m_socket;
- signals:
- //成功连接服务器的信号
- void connectSuccessfully();
- //断开服务器连接信号
- void connectDestroyed();
- //发送进度
- int GetProgressValue(int value);
-
- };
-
- #endif // SENDFILE_H

任务实现:
-
- #include "sendfile.h"
-
- #include <QFile>
- #include <QFileInfo>
- #include <QHostAddress>
-
- SendFile::SendFile(QObject *parent)
- : QObject{parent}
- {
-
- }
-
- void SendFile::connectServer( QString ip,unsigned short port)
- {
- m_socket=new QTcpSocket;
- m_socket->connectToHost(QHostAddress(ip),port);
- //QTcpSocket::connected该信号属于子线程,无法直接在主线程中调用
- //于是通过信号槽机制,定义一个SendFile的信号,将子线程的信号传递给主线程
- connect(m_socket, &QTcpSocket::connected, this, &SendFile::connectSuccessfully);
- connect(m_socket, &QTcpSocket::disconnected, this, [=](){
- m_socket->close();
- m_socket->deleteLater();
- emit connectDestroyed();
- });
- }
-
- void SendFile::sendFile(QString filePath)
- {
- QFile file(filePath);
- file.open(QFile::ReadOnly);
- QFileInfo fileinfo(filePath);
- int filesize = fileinfo.size();
- int curSize = 0;
- while (!file.atEnd()) {
- //在传输文件之前,第一次向套接字中写入文件大小,以便接收方可以知道需要接收多少数据
- if(curSize==0)
- {
- m_socket->write((char*) &filesize, 4); //用4个字节表示文件大小
- }
- QByteArray line = file.readLine();
- m_socket->write(line); //向套接字中写入数据
- curSize+=line.size();
- int progressValue = (curSize/filesize)*100; //进度值
- emit GetProgressValue(progressValue);
- }
- }
-

服务器UI
服务器主窗口头文件:
-
- #ifndef RECEIVEWINDOW_H
- #define RECEIVEWINDOW_H
-
- #include <QMainWindow>
- #include <QTcpServer>
- #include <QTcpSocket>
-
- QT_BEGIN_NAMESPACE
- namespace Ui { class receiveWindow; }
- QT_END_NAMESPACE
-
- class receiveWindow : public QMainWindow
-
- {
- Q_OBJECT
-
- public:
- receiveWindow(QWidget *parent = nullptr);
- ~receiveWindow();
- signals:
- void newSocket(QTcpSocket *socket);
-
- private slots:
- //启动监听
- void on_PortpushButton_clicked();
-
- private:
- Ui::receiveWindow *ui;
- QTcpServer *m_server;
- };
-
- #endif // RECEIVEWINDOW_H

实现:
-
- #include "receivewindow.h"
- #include "ui_receivewindow.h"
- #include <QHostAddress>
- #include <QMessageBox>
-
- #include "receivefilethread.h"
-
- receiveWindow::receiveWindow(QWidget *parent)
- : QMainWindow(parent)
- , ui(new Ui::receiveWindow)
- {
- ui->setupUi(this);
- this->ui->PortlineEdit->setText("8080");
- m_server= new QTcpServer(this);
- connect(m_server, &QTcpServer::newConnection, this, [=](){
- QTcpSocket *socket = m_server->nextPendingConnection();
- //将在主线程生成的套接字对象传入接收文件的子线程中
- ReceiveFileThread *thread = new ReceiveFileThread;
- connect(this, &receiveWindow::newSocket, thread, &ReceiveFileThread::generateSocket);
- emit newSocket(socket);
- thread->start();
- //接受子线程接收完毕信号
- connect(thread, &ReceiveFileThread::receiveFinished, this, [=](){
- thread->quit();
- thread->wait();
- thread->deleteLater();
- socket->close();
- socket->deleteLater();
- QMessageBox::information(this,"提示","接收完毕");
- });
- });
- }
-
- receiveWindow::~receiveWindow()
- {
- delete ui;
- }
-
-
-
- void receiveWindow::on_PortpushButton_clicked()
- {
- unsigned short port = this->ui->PortlineEdit->text().toUShort();
- m_server->listen(QHostAddress::Any, port);
- QMessageBox::information(this, "提示","服务器已启动");
- }
-

服务器端用子线程接受文件。
子线程头文件:(重载run方法用于启动子线程)
-
- #ifndef RECEIVEFILETHREAD_H
- #define RECEIVEFILETHREAD_H
-
-
- #include <QObject>
- #include <QTcpSocket>
- #include <QThread>
-
- class ReceiveFileThread : public QThread
- {
- Q_OBJECT
- public:
- explicit ReceiveFileThread(QObject *parent = nullptr);
- void run() override;
- void generateSocket(QTcpSocket *socket);
- private:
- QTcpSocket *m_socket;
- signals:
- void receiveFinished();
- };
-
- #endif // RECEIVEFILETHREAD_H

子线程实现:
-
- #include "receivefilethread.h"
- #include <QFile>
- ReceiveFileThread::ReceiveFileThread(QObject *parent)
- : QThread{parent}
- {
-
- }
-
- void ReceiveFileThread::generateSocket(QTcpSocket *socket)
- {
- this->m_socket=socket;
- }
-
- void ReceiveFileThread::run()
- {
-
- //创建文件
- QFile *file= new QFile("receive.txt");
- file->open(QFile::WriteOnly);
- //写入文件
- int total=0;
- int count=0;
- QString name;
- connect(m_socket,&QTcpSocket::readyRead, this,[&](){
- //第一次接收的数据为文件大小
- if(count==0){
- m_socket->read((char *)&total,4);
- }
- if(count==4){
- name= m_socket->readAll();
- }
-
- QByteArray all = m_socket->readAll();
- count += all.size(); //总大小
- file->write(all);
- //判断数据是否接收完
- if(count==total)
- {
- m_socket->close();
- m_socket->deleteLater();
- file->close();
- file->deleteLater();
- emit receiveFinished(); //发出接收完毕信号给主线程
- }
- });
- //子线程进入循环,防止线程运行完了但是文件没有接收
- exec();
-
- }
-
-

Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。