欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Qt多線程實(shí)現(xiàn)網(wǎng)絡(luò)發(fā)送文件功能

 更新時(shí)間:2022年08月22日 12:05:07   作者:xundao_803817  
這篇文章主要為大家詳細(xì)介紹了Qt多線程實(shí)現(xiàn)網(wǎng)絡(luò)發(fā)送文件功能,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下

本文實(shí)例為大家分享了Qt多線程實(shí)現(xiàn)網(wǎng)絡(luò)發(fā)送文件功能的具體代碼,供大家參考,具體內(nèi)容如下

客戶端給服務(wù)器發(fā)送文件,服務(wù)器進(jìn)行接收文件的簡(jiǎn)單操作

1. 服務(wù)器

1. 創(chuàng)建QTcpServer 類的對(duì)象

QTcpServer * server = new QTcpServer(this);

2. 進(jìn)行監(jiān)聽

bool QTcpServer::listen(const QHostAddress &address = QHostAddress::Any, quint16 port = 0)

3. 通過接收 QTcpServer 發(fā)出的 newConnection 的信號(hào),進(jìn)行下一步操作

[signal] void QTcpServer::newConnection()

4. 通過調(diào)用  nextPendingConnection 方法獲取套接字

// 通過 this->m_server 調(diào)用 nextPendConnection
QTcpSocket * socket = server->nextPendingConnection();

5. 接收客戶端發(fā)來是消息 通過 [signal] void QIODevice::readyRead() 信號(hào)

6.客戶端下線   [signal] void QAbstractSocket::disconnected() 信號(hào) 表示

創(chuàng)建一個(gè)子線程類,繼承 QThread ,重寫父類的run() 方法

在run方法中,創(chuàng)建文件,接收客戶端發(fā)的文件寫進(jìn)創(chuàng)建的文件中;

接收文件時(shí),要先獲取第一次客戶端發(fā)來的文件大??;

獲取客戶端第一次發(fā)來的文件大小

// 進(jìn)行接收數(shù)據(jù)的時(shí)候,需要知道客戶端發(fā)來的文件的大小
// 先將客戶端第一次發(fā)來的數(shù)據(jù)的大小讀取出來
static int count = 0; ? // 判斷是否是客戶端第一次發(fā)來的數(shù)據(jù)
static int total = 0; ? // 記錄文件的大小
? ? ? ? if(count == 0)
? ? ? ? {
? ? ? ? ? ? this->m_tcp->read((char*)&total, 4); ? ?// 獲取文件大小
? ? ? ? }

創(chuàng)建子線程類 并啟動(dòng)子線程

// 創(chuàng)建子線程類對(duì)象
MyQThread * myqtread = new MyQThread;
// 啟動(dòng)子線程
myqtread->start();

服務(wù)端代碼:

widget.h 主線程頭文件

#ifndef WIDGET_H
#define WIDGET_H
?
#include <QWidget>
#include <QTcpServer>
?
namespace Ui {
class Widget;
}
?
class Widget : public QWidget
{
? ? Q_OBJECT
public:
? ? explicit Widget(QWidget *parent = 0);
? ? ~Widget();
private slots:
? ? void on_listenBtn_clicked();
private:
? ? // 創(chuàng)建QTcpServer 類的對(duì)象
? ? QTcpServer * m_server;
private:
? ? Ui::Widget *ui;
};
?
#endif // WIDGET_H

widget.cpp  主線程:

#include "widget.h"
#include "ui_widget.h"
?
#include "myqthread.h"
#include <QMessageBox>
?
Widget::Widget(QWidget *parent) :
? ? QWidget(parent),
? ? ui(new Ui::Widget)
{
? ? ui->setupUi(this);
?
? ? // 設(shè)置端口號(hào)
? ? ui->port->setText("8989");
? ? // 利用多線程進(jìn)行鏈接服務(wù)器
? ? // 1. 需要?jiǎng)?chuàng)建一個(gè)線程類的子類 ,讓其繼承Qt中的線程QThread
? ? // 2. 重寫父類的run() 方法,在該函數(shù)內(nèi)部編寫子線程要處理的具體業(yè)務(wù)流程
? ? // 3. 在主線程中創(chuàng)建子線程對(duì)象,new 一個(gè)就可以
? ? // 4. 啟動(dòng)子線程,調(diào)用start() 方法
? ? // 實(shí)例化QTcpServer 對(duì)象
? ? this->m_server = new QTcpServer(this);
? ? // 檢驗(yàn)是否接收客戶端的連接
? ? connect(this->m_server, &QTcpServer::newConnection, this, [=]()
? ? {
? ? ? ? // 獲取套接字
? ? ? ? QTcpSocket * tcp = this->m_server->nextPendingConnection();
? ? ? ? // 創(chuàng)建子線程類對(duì)象
? ? ? ? MyQThread * myqtread = new MyQThread(tcp);
? ? ? ? // 啟動(dòng)子線程
? ? ? ? myqtread->start();
? ? ? ? // 獲取子線程中發(fā)來的客戶端端口的消息
? ? ? ? connect(myqtread, &MyQThread::ClientDisconnect, this, [=]()
? ? ? ? {
? ? ? ? ? ? //彈出對(duì)話框提示
? ? ? ? ? ? QMessageBox::warning(this, "警告", "客戶端已斷開連接...");
? ? ? ? });
? ? ? ? // 接收接收完客戶端的信號(hào)
? ? ? ? connect(myqtread, &MyQThread::OverRecveid, this, [=]()
? ? ? ? {
? ? ? ? ? ? //彈出對(duì)話框提示
? ? ? ? ? ? QMessageBox::information(this, "提示", "已接收文客戶端發(fā)來的數(shù)據(jù)");
? ? ? ? ? ? // 關(guān)閉套接字
? ? ? ? ? ? tcp->close();
? ? ? ? ? ? // 釋放
? ? ? ? ? ? tcp->deleteLater();
? ? ? ? ? ? // 釋放線程
? ? ? ? ? ? myqtread->quit();
? ? ? ? ? ? myqtread->wait();
? ? ? ? ? ? myqtread->deleteLater();
? ? ? ? });
? ? });
}
?
Widget::~Widget()
{
? ? delete ui;
}
// 點(diǎn)擊監(jiān)聽按鈕 進(jìn)行監(jiān)聽 按鈕轉(zhuǎn)到槽的方式
void Widget::on_listenBtn_clicked()
{
? ? //獲取端口號(hào)
? ? unsigned short port = ui->port->text().toUShort();
? ? //利用this->m_s 調(diào)用listen 進(jìn)行監(jiān)聽
? ? this->m_server->listen(QHostAddress::Any, port);
}

myqthread.h 子線程頭文件

#ifndef MYQTHREAD_H
#define MYQTHREAD_H
?
//#include <QObject>
?
#include <QTcpSocket>
#include <QThread>
?
class MyQThread : public QThread
{
? ? Q_OBJECT
public:
? ? explicit MyQThread(QTcpSocket *tcp, QObject *parent = nullptr);
?
? ? // 2.重寫QThread 類中的受保護(hù)成員 run() 方法
protected:
? ? void run();
?
public:
? ? // 自定義套接字對(duì)象 記錄主線程傳進(jìn)的套接字對(duì)象 tcp
? ? QTcpSocket * m_tcp;
?
signals:
? ? // 自定義信號(hào) 將服務(wù)器接收完客戶端發(fā)來的數(shù)據(jù) 告訴主線程
? ? void OverRecveid();
? ? // 自定義信號(hào) 將客戶端斷開連接 告訴主線程
? ? void ClientDisconnect();
?
public slots:
};
?
#endif // MYQTHREAD_H

myqthread.cpp 子線程文件

#include "myqthread.h"
?
#include <QFile>
?
MyQThread::MyQThread(QTcpSocket *tcp, QObject *parent) : QThread(parent)
{
? ? this->m_tcp = tcp;
}
// 2.重寫QThread 類中的受保護(hù)成員 run() 方法
void MyQThread::run()
{
? ? // 1.創(chuàng)建文件 打開文件
? ? QFile * file = new QFile("recv.txt");
? ? file->open(QFile::WriteOnly); ? // 以只寫的方式打開文件
? ? // 2.檢驗(yàn)是否進(jìn)行讀寫
? ? connect(this->m_tcp, &QTcpSocket::readyRead, this, [=]()
? ? {
? ? ? ? // 進(jìn)行接收數(shù)據(jù)的時(shí)候,需要知道客戶端發(fā)來的文件的大小
? ? ? ? // 先將客戶端第一次發(fā)來的數(shù)據(jù)的大小讀取出來
? ? ? ? static int count = 0; ? // 判斷是否是客戶端第一次發(fā)來的數(shù)據(jù)
? ? ? ? static int total = 0; ? // 記錄文件的大小
? ? ? ? if(count == 0)
? ? ? ? {
? ? ? ? ? ? this->m_tcp->read((char*)&total, 4); ? ?// 獲取文件大小
? ? ? ? }
? ? ? ? // 將剩下的數(shù)據(jù)全部讀取出來
? ? ? ? // 獲取客戶端發(fā)來的數(shù)據(jù)
? ? ? ? QByteArray recvClient = this->m_tcp->readAll(); // 全部接收
? ? ? ? // 將讀取的數(shù)據(jù)的量記錄到count中
? ? ? ? count += recvClient.size();
? ? ? ? // 將數(shù)據(jù)寫進(jìn)文件中
? ? ? ? file->write(recvClient);
? ? ? ? // 判斷服務(wù)器是否把客戶端發(fā)來的數(shù)據(jù)全部讀取完
? ? ? ? if(count == total)
? ? ? ? {
? ? ? ? ? ? // 關(guān)閉套接字
? ? ? ? ? ? this->m_tcp->close();
? ? ? ? ? ? // 釋放套接字
? ? ? ? ? ? this->m_tcp->deleteLater();
? ? ? ? ? ? // 關(guān)閉文件
? ? ? ? ? ? file->close();
? ? ? ? ? ? file->deleteLater();
? ? ? ? ? ? // 自定義一個(gè)信號(hào) 告訴主線程文件 已接收完畢
? ? ? ? ? ? emit OverRecveid();
? ? ? ? }
? ? });
? ? // 3.檢驗(yàn)客戶端是否斷開連接
? ? connect(m_tcp, &QTcpSocket::disconnected, this, [=]()
? ? {
? ? ? ? // 將客戶端斷開連接 發(fā)送給主線程
? ? ? ? emit this->ClientDisconnect();
? ? });
? ? // 調(diào)用 exec 進(jìn)入事件循環(huán) 阻塞
? ? exec();
}

2.客戶端

1. 綁定 ip 和 端口號(hào)

[virtual] void QAbstractSocket::connectToHost(const QString &hostName, quint16 port, OpenMode openMode = ReadWrite, NetworkLayerProtocol protocol = AnyIPProtocol)

2. 連接服務(wù)器

[signal] void QAbstractSocket::connected()

3. 通過套接字 調(diào)用 write方法發(fā)送消息給服務(wù)器

qint64 QIODevice::write(const char *data, qint64 maxSize)

4. 斷開連接

[signal] void QAbstractSocket::disconnected()

利用多線程實(shí)現(xiàn) 選擇文件 發(fā)送文件                          

利用第二種多線程的方法                                

1.創(chuàng)建一個(gè)新的類,讓這個(gè)類從QObject中派生                  
2.在這個(gè)新的類中添加一個(gè)公有的成員函數(shù),函數(shù)體是我們要子線程中執(zhí)行的業(yè)務(wù)邏輯    
3.在主線程中創(chuàng)建一個(gè)QThread對(duì)象,這個(gè)就是子線程的對(duì)象            
4.在主線程中創(chuàng)建一個(gè)工作類的對(duì)象                          
5.將工作類對(duì)象移動(dòng)到子線程對(duì)象中,需要調(diào)用QObject類提供的moveThread
6.啟動(dòng)子線程,調(diào)用start() 這個(gè)線程啟動(dòng)了,當(dāng)時(shí)移動(dòng)到線程中的對(duì)象并沒有工作
7.調(diào)用工作類的對(duì)象函數(shù),讓這個(gè)函數(shù)開始執(zhí)行,這個(gè)時(shí)候是在移動(dòng)到那個(gè)子線程中運(yùn)行的。       

客戶端代碼: 

mythread.h 任務(wù)類頭文件

#ifndef MYTHREAD_H
#define MYTHREAD_H
?
#include <QObject>
#include <QTcpSocket>
?
class MyThread : public QObject
{
? ? Q_OBJECT
public:
? ? explicit MyThread(QObject *parent = nullptr);
?
? ? // 連接服務(wù)器
? ? void connectToServer(unsigned short port, QString ip);
? ? // 發(fā)送文件
? ? void SendFile(QString path);
?
private:
? ? // 創(chuàng)建QTcpSocket 類的對(duì)象
? ? QTcpSocket * m_socket;
?
signals:
? ? // 自定義一個(gè)信息 告訴主線程 成功連接到服務(wù)器
? ? void ConnectOK();
?
? ? // 自定義一個(gè)信號(hào) 告訴主線程服務(wù)器已斷開連接
? ? void gameOver();
?
? ? // 自定義一個(gè)信號(hào) 將獲取的百分比發(fā)送給主線程
? ? void SendPercent(int);
?
public slots:
};
?
#endif // MYTHREAD_H

mythread.cpp 任務(wù)類文件

#include "mythread.h"
?
#include <QFileInfo>
#include <QMessageBox>
?
MyThread::MyThread(QObject *parent) : QObject(parent)
{
?
}
// 連接服務(wù)器
void MyThread::connectToServer(unsigned short port, QString ip)
{
? ? // 實(shí)例化socket類的對(duì)象
? ? this->m_socket = new QTcpSocket(this);
? ? // 嘗試與服務(wù)器取得連接 綁定IP 和端口號(hào)
? ? this->m_socket->connectToHost(ip, port);
? ? // 檢驗(yàn)是否成功與服務(wù)器取等連接
? ? connect(this->m_socket, &QTcpSocket::connected, this, [=]()
? ? {
? ? ? ? emit this->ConnectOK(); // 自定義一個(gè)信號(hào) 告訴主線程 成功連接上服務(wù)器
? ? });
? ? // 檢驗(yàn)服務(wù)器是否斷開連接
? ? connect(this->m_socket, &QTcpSocket::disconnected, this, [=]()
? ? {
? ? ? ? this->m_socket->close(); ? ?// 關(guān)閉套接字
? ? ? ? emit this->gameOver(); ? ? ?// 發(fā)送信號(hào) 告訴主線程 服務(wù)器已斷開連接
? ? });
}
// 發(fā)送文件
void MyThread::SendFile(QString path)
{
? ? // 1.獲取文件大小
? ? QFileInfo info(path);
? ? int fileSize = info.size();
? ? // 2.打開文件
? ? QFile file(path);
? ? bool ret = file.open(QFile::ReadOnly);
? ? if(!ret)
? ? {
? ? ? ? QMessageBox::warning(NULL, "警告", "打開文件失敗");
? ? ? ? return; // 退出函數(shù)
? ? }
? ? // 判斷什么時(shí)候讀完文件
? ? while(!file.atEnd())
? ? {
? ? ? ? // 第一次發(fā)送文件的時(shí)候 將文件的大小發(fā)送給服務(wù)器
? ? ? ? // 定義一個(gè)標(biāo)記 當(dāng)標(biāo)記為0時(shí), 表示第一次發(fā)送文件
? ? ? ? static int num = 0;
? ? ? ? if(num == 0)
? ? ? ? {
? ? ? ? ? ? this->m_socket->write((char*)&fileSize, 4); // 將文件大小發(fā)送給服務(wù)器
? ? ? ? }
? ? ? ? // 在循環(huán)體中 每次讀取一行
? ? ? ? QByteArray line = file.readLine();
? ? ? ? // 每次發(fā)送一次數(shù)據(jù),就將發(fā)送的數(shù)據(jù)的量記錄下來 用于更新進(jìn)度條
? ? ? ? num += line.size();
? ? ? ? // 基于num值 計(jì)算百分比
? ? ? ? int percent = (num*100/fileSize);
? ? ? ? // 將百分比發(fā)送給主線程
? ? ? ? emit this->SendPercent(percent);
? ? ? ? // 將讀取的數(shù)據(jù)通過套接字對(duì)象發(fā)送給服務(wù)器
? ? ? ? this->m_socket->write(line);
? ? }
}

widget.h 主線程頭文件

#ifndef WIDGET_H
#define WIDGET_H
?
#include <QWidget>
?
namespace Ui {
class Widget;
}
?
class Widget : public QWidget
{
? ? Q_OBJECT
?
public:
? ? explicit Widget(QWidget *parent = 0);
? ? ~Widget();
?
signals:
? ? // 自定義一個(gè)信號(hào) 告訴子線程進(jìn)行鏈接服務(wù)器
? ? void TellToConnect(unsigned short port, QString ip);
? ? // 自定義一個(gè)信號(hào) 將選中的文件路徑發(fā)送給任務(wù)類
? ? void SendToFile(QString);
?
private slots:
? ? void on_connectBtn_clicked();
?
? ? void on_selectBtn_clicked();
?
? ? void on_sendBtn_clicked();
?
private:
? ? QString m_path;
private:
? ? Ui::Widget *ui;
};
?
#endif // WIDGET_H

widget.cpp

#include "widget.h"
#include "ui_widget.h"
?
#include <QFileDialog>
#include <QMessageBox>
#include <QThread>
#include "mythread.h"
?
Widget::Widget(QWidget *parent) :
? ? QWidget(parent),
? ? ui(new Ui::Widget)
{
? ? ui->setupUi(this);
?
? ? // 利用多線程實(shí)現(xiàn) 選擇文件 發(fā)送文件
? ? // 利用第二種多線程的方法
? ? // 1.創(chuàng)建一個(gè)新的類,讓這個(gè)類從QObject中派生
? ? // 2.在這個(gè)新的類中添加一個(gè)公有的成員函數(shù),函數(shù)體是我們要子線程中執(zhí)行的業(yè)務(wù)邏輯
? ? // 3.在主線程中創(chuàng)建一個(gè)QThread對(duì)象,這個(gè)就是子線程的對(duì)象
? ? // 4.在主線程中創(chuàng)建一個(gè)工作類的對(duì)象
? ? // 5.將工作類對(duì)象移動(dòng)到子線程對(duì)象中,需要調(diào)用QObject類提供的moveThread方法
? ? // 6.啟動(dòng)子線程,調(diào)用start() 這個(gè)線程啟動(dòng)了,當(dāng)時(shí)移動(dòng)到線程中的對(duì)象并沒有工作
? ? // 7.調(diào)用工作類的對(duì)象函數(shù),讓這個(gè)函數(shù)開始執(zhí)行,這個(gè)時(shí)候是在移動(dòng)到那個(gè)子線程中運(yùn)行的。
?
? ? // 1.創(chuàng)建QThread對(duì)象
? ? QThread *t = new QThread;
? ? // 2.創(chuàng)建任務(wù)類的對(duì)象
? ? MyThread * working = new MyThread;
? ? // 3.將任務(wù)類對(duì)象移動(dòng)到子線程中
? ? working->moveToThread(t);
? ? // 啟動(dòng)子線程
? ? t->start();
? ? // 4.設(shè)置IP 端口號(hào)
? ? ui->ip_lineEide->setText("127.0.0.1");
? ? ui->port_lineEdit->setText("8989");
? ? // 5.設(shè)置進(jìn)度條
? ? ui->progressBar->setRange(0, 100); ?// 進(jìn)度條的范圍
? ? ui->progressBar->setValue(0); ? ? ? // 初始化為0
? ? // 6.更新進(jìn)度條 通過連接任務(wù)類發(fā)來的信號(hào) 實(shí)現(xiàn)
? ? connect(working, &MyThread::SendPercent, ui->progressBar, &QProgressBar::setValue);
? ? // 7.接收任務(wù)類發(fā)來的成功連接到服務(wù)器 信號(hào)
? ? connect(working, &MyThread::ConnectOK, this, [=]()
? ? {
? ? ? ? QMessageBox::information(this, "提示", "成功連接到服務(wù)器");
? ? ? ? // 將文件按鈕設(shè)置成不可用狀態(tài)
? ? ? ? ui->sendBtn->setDisabled(false);
? ? });
? ? // 8.連接任務(wù)類發(fā)來的斷開連接的信號(hào)
? ? connect(working, &MyThread::gameOver, this, [=]()
? ? {
? ? ? ? QMessageBox::warning(this, "警告", "服務(wù)器已斷開連接");
? ? ? ? //釋放支援
? ? ? ? t->quit();
? ? ? ? t->wait();
? ? ? ? t->deleteLater();
? ? ? ? working->deleteLater();
? ? ? ? // 將文件按鈕設(shè)置成可用狀態(tài)
? ? ? ? ui->sendBtn->setDisabled(true);
? ? });
? ? // 7.將信號(hào)和工作類對(duì)象中的任務(wù)函數(shù)連接
? ? connect(this, &Widget::TellToConnect, working, &MyThread::connectToServer);
? ? // 8.將文件路徑發(fā)給任務(wù)函數(shù)
? ? connect(this, &Widget::SendToFile, working, &MyThread::SendFile);
? ? // 9.將發(fā)送文件按鈕設(shè)置成可用狀態(tài)
? ? ui->sendBtn->setDisabled(true);
}
?
Widget::~Widget()
{
? ? delete ui;
}
// 連接服務(wù)器
void Widget::on_connectBtn_clicked()
{
? ? // 獲取ip 和 端口號(hào)
? ? QString ip = ui->ip_lineEide->text();
? ? unsigned short port = ui->port_lineEdit->text().toShort();
? ? // 將ip 和 端口號(hào) 發(fā)送取出
? ? emit this->TellToConnect(port, ip);
? ? // 將發(fā)送文件按鈕設(shè)置成不可用狀態(tài)
? ? ui->sendBtn->setDisabled(false);
}
// 選中文件
void Widget::on_selectBtn_clicked()
{
? ? m_path = QFileDialog::getOpenFileName(); ?// 打開文件選擇對(duì)話框
? ? // 判斷選中的對(duì)話框不能為空
? ? if(m_path.isEmpty())
? ? ? ? QMessageBox::warning(this, "警告", "選中要發(fā)送的文件不能為空");
? ? // 將選中的文件路徑顯示到單行編輯框中
? ? ui->filePath_lineEdit->setText(m_path);
}
// 發(fā)送文件
void Widget::on_sendBtn_clicked()
{
? ? // 將選中的文件路徑發(fā)送給任務(wù)類
? ? emit this->SendToFile(m_path);
}

程序運(yùn)行結(jié)果:

以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

最新評(píng)論