赞
踩
一、写一个类继承QThread类,并重写run()函数,并在主线程中生成一个ChildThread的实例,并调用对象的start()函数
每次新建一个线程都需要继承QThread,实现一个新类,要自己进行资源管理,线程释放和删除
二、定义一个普通的QObject派生类Worker,然后将其对象move到创建的QThread类中,调用线程的start()函数
主线程如果要在子线程中运行计算必须通过发信号的方式调用,或者通过控件的信号
实现文件传输功能
服务器端:
主线程:
class Widget : public QWidget
{
Q_OBJECT
public:
Widget(QWidget *parent = nullptr);
~Widget();
private:
Ui::WidgetClass *ui;
QTcpServer* serv;
public slots:
void setListen_clicked();
};
Widget::Widget(QWidget *parent) : QWidget(parent) , ui(new Ui::WidgetClass()) { //初始化 ui->setupUi(this); ui->port->setText("8899"); setWindowTitle("服务器"); serv = new QTcpServer(this); //监听到新连接时接受新连接 connect(serv, &QTcpServer::newConnection, this, [=]() { QTcpSocket* conntcp = serv->nextPendingConnection(); ui->msg->append("与客户端建立连接"); //创建子线程,并运行 ReceiveFile* subThread = new ReceiveFile(conntcp); subThread->start(); //任务完成后,回收子线程资源 connect(subThread, &ReceiveFile::over, this, [=]() { subThread->exit(); subThread->wait(); subThread->deleteLater(); ui->msg->append("文件接收完毕"); QMessageBox::information(this, "文件接收", "文件接收完毕"); }); }); //按钮处理 connect(ui->setListen, &QPushButton::clicked, this, &Widget::setListen_clicked); } Widget::~Widget() { delete ui; } void Widget::setListen_clicked() { unsigned short port = ui->port->text().toUShort(); serv->listen(QHostAddress::Any, port); }
子线程接受文件
class ReceiveFile : public QThread
{
Q_OBJECT
public:
ReceiveFile(QTcpSocket* tcp, QObject *parent=nullptr);
~ReceiveFile();
protected:
void run() override;//重写线程运行函数
private:
QTcpSocket* tcp_;
signals:
void over();
};
ReceiveFile::ReceiveFile(QTcpSocket* tcp, QObject* parent) : QThread(parent), tcp_(tcp) {} ReceiveFile::~ReceiveFile() {} void ReceiveFile::run() { QFile* file = new QFile("recv.txt"); file->open(QFile::WriteOnly); //就绪时读取,并写入文件 connect(tcp_, &QTcpSocket::readyRead, this, [=]() { static int count = 0; static int total = 0; if (count == 0) { tcp_->read((char*)&total, 4);//读取文件大小 } QByteArray all = tcp_->readAll(); count += all.size(); file->write(all); //写完释放资源 if (count == total) { tcp_->close(); tcp_->deleteLater(); file->close(); file->deleteLater(); emit over(); } }); exec();//事件循环 }
客户端:
主线程
class Widget : public QWidget { Q_OBJECT public: Widget(QWidget *parent = nullptr); ~Widget(); private: Ui::WidgetClass *ui; public slots: void connect_clicked(); void sendFile_clicked(); void setFile_clicked(); signals: void startConnect(QString ip, unsigned short port); void sendFile(QString path); };
Widget::Widget(QWidget *parent) : QWidget(parent) , ui(new Ui::WidgetClass()) { //初始化 ui->setupUi(this); ui->port->setText("8899"); ui->ip->setText("127.0.0.1"); setWindowTitle("客户端"); ui->progressBar->setRange(0, 100); ui->progressBar->setValue(0); //创建子线程,将运行对象放入线程中 QThread* t = new QThread; SendFile* worker = new SendFile; worker->moveToThread(t); //点击按钮,子线程发送文件 connect(this, &Widget::sendFile, worker, &SendFile::sendFile); //点击按钮,子线程连接服务器 connect(this, &Widget::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); //按钮处理 connect(ui->connect, &QPushButton::clicked, this, &Widget::connect_clicked); connect(ui->setFile, &QPushButton::clicked, this, &Widget::setFile_clicked); connect(ui->sendFile, &QPushButton::clicked, this, &Widget::sendFile_clicked); //子线程开始运行 t->start(); } Widget::~Widget() { delete ui; } void Widget::connect_clicked() { QString ip = ui->ip->text(); unsigned short port = ui->port->text().toUShort(); emit startConnect(ip, port); } void Widget::setFile_clicked() { QString path = QFileDialog::getOpenFileName();//文件对话框 if (path.isEmpty()) { QMessageBox::warning(this, "打开文件", "文件路径不能为空"); return; } ui->filePath->setText(path); } void Widget::sendFile_clicked() { emit sendFile(ui->filePath->text()); }
子线程连接服务器,发送文件
class SendFile : public QObject { Q_OBJECT public: SendFile(QObject* parent = nullptr); ~SendFile(); void connectServer(QString ip, unsigned short port); void sendFile(QString path); private: QTcpSocket* tcp; signals: void connectOk(); void gameover(); void curPercent(int num); };
SendFile::SendFile(QObject* parent) : QObject(parent) { } SendFile::~SendFile() { } void SendFile::connectServer(QString ip, unsigned short port) { tcp = new QTcpSocket; tcp->connectToHost(QHostAddress(ip), port); //连接成功,通知主线程 connect(tcp, &QTcpSocket::connected, this, &SendFile::connectOk); //断开连接,回收资源,通知主线程 connect(tcp, &QTcpSocket::disconnected, this, [=]() { tcp->close(); 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) { tcp->write((char*)&filesize,4);//先发送文件大小 } QByteArray line = file.readLine();//按行读取 num += line.size(); int percent = (num * 100 / filesize);//百分比 emit curPercent(percent); tcp->write(line); } }
结果:
参考:
Qt多线程网络通信–b站,爱编程的大丙
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。