[08.QT network communication multithreading]

QT network communication multi-thread

    • QThread thread creation method
    • the code

QThread thread creation method

1. Write a class that inherits the QThread class, rewrite the run() function, and generate an instance of ChildThread in the main thread, and call the start() function of the object
Every time you create a new thread, you need to inherit QThread, implement a new class, and perform resource management, thread release and deletion by yourself.
2. Define an ordinary QObject derived class Worker, then move its object to the created QThread class, and call the start() function of the thread
If the main thread wants to run calculations in the child thread, it must be called by signaling, or through the signal of the control

Code

Implement file transfer function

Service-Terminal:
main thread:

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())
{<!-- -->
    //initialization
    ui->setupUi(this);
    ui->port->setText("8899");
    setWindowTitle("Server");

    serv = new QTcpServer(this);
    //Accept new connections when listening to new connections
    connect(serv, &QTcpServer::newConnection, this, [=]()
        {<!-- -->
            QTcpSocket* conntcp = serv->nextPendingConnection();
            ui->msg->append("Establish a connection with the client");
            //Create a child thread and run it
            ReceiveFile* subThread = new ReceiveFile(conntcp);
            subThread->start();
            //After the task is completed, recycle the child thread resources
            connect(subThread, & amp;ReceiveFile::over, this, [=]() {<!-- -->
                subThread->exit();
                subThread->wait();
                subThread->deleteLater();
                ui->msg->append("The file has been received");
                QMessageBox::information(this, "File received", "File received");
                });
        });
    // button handling
    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);
}

Child thread accepts files

class ReceiveFile : public QThread
{<!-- -->
Q_OBJECT

public:
ReceiveFile(QTcpSocket* tcp, QObject *parent=nullptr);
~ReceiveFile();
protected:
void run() override;//Rewrite thread running function
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);
// read and write to file when ready
connect(tcp_, &QTcpSocket::readyRead, this, [=]() {<!-- -->
static int count = 0;
static int total = 0;
if (count == 0) {<!-- -->
tcp_->read((char*) & amp;total, 4);//read file size
}
QByteArray all = tcp_->readAll();
count + = all. size();
file->write(all);
//Release resources after writing
if (count == total) {<!-- -->
tcp_->close();
tcp_->deleteLater();
file->close();
file->deleteLater();
emit over();
}
});
exec();//event loop
}

client:
main thread

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())
{<!-- -->
    //initialization
    ui->setupUi(this);
    ui->port->setText("8899");
    ui->ip->setText("127.0.0.1");
    setWindowTitle("Client");
    ui->progressBar->setRange(0, 100);
    ui->progressBar->setValue(0);
    //Create a child thread and put the running object into the thread
    QThread* t = new QThread;
    SendFile* worker = new SendFile;
    worker->moveToThread(t);
    //Click the button, the child thread sends the file
    connect(this, & amp;Widget::sendFile, worker, & amp;SendFile::sendFile);
    //Click the button, the child thread connects to the server
    connect(this, & amp;Widget::startConnect, worker, & amp;SendFile::connectServer);
    //The connection is successful, the main thread prints the message
    connect(worker, & amp;SendFile::connectOk, this, [=]() {<!-- -->
        QMessageBox::information(this, "connected to the server", "connected successfully");//message dialog box
        });
    //Disconnect, the main thread recycles resources
    connect(worker, & amp;SendFile::gameover, this, [=]() {<!-- -->
        //Release resources
        t->quit();
        t->wait();
        worker->deleteLater();
        t->deleteLater();
        });
    //The main thread displays the sending progress
    connect(worker, &SendFile::curPercent, ui->progressBar, &QProgressBar::setValue);
    // button handling
    connect(ui->connect, &QPushButton::clicked, this, &Widget::connect_clicked);
    connect(ui->setFile, & amp;QPushButton::clicked, this, & amp;Widget::setFile_clicked);
    connect(ui->sendFile, &QPushButton::clicked, this, &Widget::sendFile_clicked);
    //The child thread starts running
    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();//File dialog
    if (path.isEmpty()) {<!-- -->
        QMessageBox::warning(this, "Open the file", "The file path cannot be empty");
        return;
    }
    ui->filePath->setText(path);
}

void Widget::sendFile_clicked() {<!-- -->
    emit sendFile(ui->filePath->text());
}

The child thread connects to the server and sends the file

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);
    //The connection is successful, notify the main thread
    connect(tcp, & amp; QTcpSocket::connected, this, & amp; SendFile::connectOk);
    //Disconnect, recycle resources, and notify the main thread
    connect(tcp, &QTcpSocket::disconnected, this, [=]() {<!-- -->
        tcp->close();
        tcp->deleteLater();
        emit gameover();
        });
}

void SendFile::sendFile(QString path)
{<!-- -->
    QFile file(path);
    QFileInfo info(path);//file information
    int filesize = info.size();//file size
    file.open(QFile::ReadOnly);//Open the file
    while (!file.atEnd()) {<!-- -->//End flag
        static int num = 0;
        if (num == 0) {<!-- -->
            tcp->write((char*) & amp;filesize,4);//Send the file size first
        }
        QByteArray line = file.readLine();//Read by line
        num + = line. size();
        int percent = (num * 100 / filesize);//percentage
        emit curPercent(percent);
        tcp->write(line);
    }
}

result:

refer to:
Qt multi-threaded network communication – station b, big C of love programming