当前位置:   article > 正文

【08.QT网络通信多线程】_qt多线程tcp通信

qt多线程tcp通信

QT网络通信多线程

QThread线程创建方法

一、写一个类继承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();
};
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
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);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40

子线程接受文件

class ReceiveFile  : public QThread
{
	Q_OBJECT

public:
	ReceiveFile(QTcpSocket* tcp, QObject *parent=nullptr);
	~ReceiveFile();
protected:
	void run() override;//重写线程运行函数
private:
	QTcpSocket* tcp_;
signals:
	void over();
};
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
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();//事件循环
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32

客户端:
主线程

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);
};
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
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());
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64

子线程连接服务器,发送文件

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);
};
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
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);
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41

结果:
在这里插入图片描述

参考:
Qt多线程网络通信–b站,爱编程的大丙

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小丑西瓜9/article/detail/305136
推荐阅读
相关标签
  

闽ICP备14008679号