<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
本文範例為大家分享了Qt多執行緒實現網路傳送檔案功能的具體程式碼,供大家參考,具體內容如下
使用者端給伺服器傳送檔案,伺服器進行接收檔案的簡單操作
1. 建立QTcpServer 類的物件
QTcpServer * server = new QTcpServer(this);
2. 進行監聽
bool QTcpServer::listen(const QHostAddress &address = QHostAddress::Any, quint16 port = 0)
3. 通過接收 QTcpServer 發出的 newConnection 的訊號,進行下一步操作
[signal] void QTcpServer::newConnection()
4. 通過呼叫 nextPendingConnection 方法獲取通訊端
// 通過 this->m_server 呼叫 nextPendConnection QTcpSocket * socket = server->nextPendingConnection();
5. 接收使用者端發來是訊息 通過 [signal] void QIODevice::readyRead() 訊號
6.使用者端下線 [signal] void QAbstractSocket::disconnected() 訊號 表示
建立一個子執行緒類,繼承 QThread ,重寫父類別的run() 方法
在run方法中,建立檔案,接收使用者端發的檔案寫進建立的檔案中;
接收檔案時,要先獲取第一次使用者端發來的檔案大小;
獲取使用者端第一次發來的檔案大小
// 進行接收資料的時候,需要知道使用者端發來的檔案的大小 // 先將使用者端第一次發來的資料的大小讀取出來 static int count = 0; // 判斷是否是使用者端第一次發來的資料 static int total = 0; // 記錄檔案的大小 if(count == 0) { this->m_tcp->read((char*)&total, 4); // 獲取檔案大小 }
建立子執行緒類 並啟動子執行緒
// 建立子執行緒類物件 MyQThread * myqtread = new MyQThread; // 啟動子執行緒 myqtread->start();
伺服器端程式碼:
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: // 建立QTcpServer 類的物件 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); // 設定埠號 ui->port->setText("8989"); // 利用多執行緒進行連結伺服器 // 1. 需要建立一個執行緒類的子類 ,讓其繼承Qt中的執行緒QThread // 2. 重寫父類別的run() 方法,在該函數內部編寫子執行緒要處理的具體業務流程 // 3. 在主執行緒中建立子執行緒物件,new 一個就可以 // 4. 啟動子執行緒,呼叫start() 方法 // 範例化QTcpServer 物件 this->m_server = new QTcpServer(this); // 檢驗是否接收使用者端的連線 connect(this->m_server, &QTcpServer::newConnection, this, [=]() { // 獲取通訊端 QTcpSocket * tcp = this->m_server->nextPendingConnection(); // 建立子執行緒類物件 MyQThread * myqtread = new MyQThread(tcp); // 啟動子執行緒 myqtread->start(); // 獲取子執行緒中發來的使用者端埠的訊息 connect(myqtread, &MyQThread::ClientDisconnect, this, [=]() { //彈出對話方塊提示 QMessageBox::warning(this, "警告", "使用者端已斷開連線..."); }); // 接收接收完使用者端的訊號 connect(myqtread, &MyQThread::OverRecveid, this, [=]() { //彈出對話方塊提示 QMessageBox::information(this, "提示", "已接收文使用者端發來的資料"); // 關閉通訊端 tcp->close(); // 釋放 tcp->deleteLater(); // 釋放執行緒 myqtread->quit(); myqtread->wait(); myqtread->deleteLater(); }); }); } Widget::~Widget() { delete ui; } // 點選監聽按鈕 進行監聽 按鈕轉到槽的方式 void Widget::on_listenBtn_clicked() { //獲取埠號 unsigned short port = ui->port->text().toUShort(); //利用this->m_s 呼叫listen 進行監聽 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 類中的受保護成員 run() 方法 protected: void run(); public: // 自定義通訊端物件 記錄主執行緒傳進的通訊端物件 tcp QTcpSocket * m_tcp; signals: // 自定義訊號 將伺服器接收完使用者端發來的資料 告訴主執行緒 void OverRecveid(); // 自定義訊號 將使用者端斷開連線 告訴主執行緒 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 類中的受保護成員 run() 方法 void MyQThread::run() { // 1.建立檔案 開啟檔案 QFile * file = new QFile("recv.txt"); file->open(QFile::WriteOnly); // 以只寫的方式開啟檔案 // 2.檢驗是否進行讀寫 connect(this->m_tcp, &QTcpSocket::readyRead, this, [=]() { // 進行接收資料的時候,需要知道使用者端發來的檔案的大小 // 先將使用者端第一次發來的資料的大小讀取出來 static int count = 0; // 判斷是否是使用者端第一次發來的資料 static int total = 0; // 記錄檔案的大小 if(count == 0) { this->m_tcp->read((char*)&total, 4); // 獲取檔案大小 } // 將剩下的資料全部讀取出來 // 獲取使用者端發來的資料 QByteArray recvClient = this->m_tcp->readAll(); // 全部接收 // 將讀取的資料的量記錄到count中 count += recvClient.size(); // 將資料寫進檔案中 file->write(recvClient); // 判斷伺服器是否把使用者端發來的資料全部讀取完 if(count == total) { // 關閉通訊端 this->m_tcp->close(); // 釋放通訊端 this->m_tcp->deleteLater(); // 關閉檔案 file->close(); file->deleteLater(); // 自定義一個訊號 告訴主執行緒檔案 已接收完畢 emit OverRecveid(); } }); // 3.檢驗使用者端是否斷開連線 connect(m_tcp, &QTcpSocket::disconnected, this, [=]() { // 將使用者端斷開連線 傳送給主執行緒 emit this->ClientDisconnect(); }); // 呼叫 exec 進入事件迴圈 阻塞 exec(); }
1. 繫結 ip 和 埠號
[virtual] void QAbstractSocket::connectToHost(const QString &hostName, quint16 port, OpenMode openMode = ReadWrite, NetworkLayerProtocol protocol = AnyIPProtocol)
2. 連線伺服器
[signal] void QAbstractSocket::connected()
3. 通過通訊端 呼叫 write方法傳送訊息給伺服器
qint64 QIODevice::write(const char *data, qint64 maxSize)
4. 斷開連線
[signal] void QAbstractSocket::disconnected()
利用多執行緒實現 選擇檔案 傳送檔案
利用第二種多執行緒的方法
1.建立一個新的類,讓這個類從QObject中派生
2.在這個新的類中新增一個公有的成員函數,函數體是我們要子執行緒中執行的業務邏輯
3.在主執行緒中建立一個QThread物件,這個就是子執行緒的物件
4.在主執行緒中建立一個工作類的物件
5.將工作類物件移動到子執行緒物件中,需要呼叫QObject類提供的moveThread
6.啟動子執行緒,呼叫start() 這個執行緒啟動了,當時移動到執行緒中的物件並沒有工作
7.呼叫工作類的物件函數,讓這個函數開始執行,這個時候是在移動到那個子執行緒中執行的。
使用者端程式碼:
mythread.h 任務類標頭檔案
#ifndef MYTHREAD_H #define MYTHREAD_H #include <QObject> #include <QTcpSocket> class MyThread : public QObject { Q_OBJECT public: explicit MyThread(QObject *parent = nullptr); // 連線伺服器 void connectToServer(unsigned short port, QString ip); // 傳送檔案 void SendFile(QString path); private: // 建立QTcpSocket 類的物件 QTcpSocket * m_socket; signals: // 自定義一個資訊 告訴主執行緒 成功連線到伺服器 void ConnectOK(); // 自定義一個訊號 告訴主執行緒伺服器已斷開連線 void gameOver(); // 自定義一個訊號 將獲取的百分比傳送給主執行緒 void SendPercent(int); public slots: }; #endif // MYTHREAD_H
mythread.cpp 任務類檔案
#include "mythread.h" #include <QFileInfo> #include <QMessageBox> MyThread::MyThread(QObject *parent) : QObject(parent) { } // 連線伺服器 void MyThread::connectToServer(unsigned short port, QString ip) { // 範例化socket類的物件 this->m_socket = new QTcpSocket(this); // 嘗試與伺服器取得連線 繫結IP 和埠號 this->m_socket->connectToHost(ip, port); // 檢驗是否成功與伺服器取等連線 connect(this->m_socket, &QTcpSocket::connected, this, [=]() { emit this->ConnectOK(); // 自定義一個訊號 告訴主執行緒 成功連線上伺服器 }); // 檢驗伺服器是否斷開連線 connect(this->m_socket, &QTcpSocket::disconnected, this, [=]() { this->m_socket->close(); // 關閉通訊端 emit this->gameOver(); // 傳送訊號 告訴主執行緒 伺服器已斷開連線 }); } // 傳送檔案 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; // 退出函數 } // 判斷什麼時候讀完檔案 while(!file.atEnd()) { // 第一次傳送檔案的時候 將檔案的大小傳送給伺服器 // 定義一個標記 當標記為0時, 表示第一次傳送檔案 static int num = 0; if(num == 0) { this->m_socket->write((char*)&fileSize, 4); // 將檔案大小傳送給伺服器 } // 在迴圈體中 每次讀取一行 QByteArray line = file.readLine(); // 每次傳送一次資料,就將傳送的資料的量記錄下來 用於更新進度條 num += line.size(); // 基於num值 計算百分比 int percent = (num*100/fileSize); // 將百分比傳送給主執行緒 emit this->SendPercent(percent); // 將讀取的資料通過通訊端物件傳送給伺服器 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: // 自定義一個訊號 告訴子執行緒進行連結伺服器 void TellToConnect(unsigned short port, QString ip); // 自定義一個訊號 將選中的檔案路徑傳送給任務類 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); // 利用多執行緒實現 選擇檔案 傳送檔案 // 利用第二種多執行緒的方法 // 1.建立一個新的類,讓這個類從QObject中派生 // 2.在這個新的類中新增一個公有的成員函數,函數體是我們要子執行緒中執行的業務邏輯 // 3.在主執行緒中建立一個QThread物件,這個就是子執行緒的物件 // 4.在主執行緒中建立一個工作類的物件 // 5.將工作類物件移動到子執行緒物件中,需要呼叫QObject類提供的moveThread方法 // 6.啟動子執行緒,呼叫start() 這個執行緒啟動了,當時移動到執行緒中的物件並沒有工作 // 7.呼叫工作類的物件函數,讓這個函數開始執行,這個時候是在移動到那個子執行緒中執行的。 // 1.建立QThread物件 QThread *t = new QThread; // 2.建立任務類的物件 MyThread * working = new MyThread; // 3.將任務類物件移動到子執行緒中 working->moveToThread(t); // 啟動子執行緒 t->start(); // 4.設定IP 埠號 ui->ip_lineEide->setText("127.0.0.1"); ui->port_lineEdit->setText("8989"); // 5.設定進度條 ui->progressBar->setRange(0, 100); // 進度條的範圍 ui->progressBar->setValue(0); // 初始化為0 // 6.更新進度條 通過連線任務類發來的訊號 實現 connect(working, &MyThread::SendPercent, ui->progressBar, &QProgressBar::setValue); // 7.接收任務類發來的成功連線到伺服器 訊號 connect(working, &MyThread::ConnectOK, this, [=]() { QMessageBox::information(this, "提示", "成功連線到伺服器"); // 將檔案按鈕設定成不可用狀態 ui->sendBtn->setDisabled(false); }); // 8.連線任務類發來的斷開連線的訊號 connect(working, &MyThread::gameOver, this, [=]() { QMessageBox::warning(this, "警告", "伺服器已斷開連線"); //釋放支援 t->quit(); t->wait(); t->deleteLater(); working->deleteLater(); // 將檔案按鈕設定成可用狀態 ui->sendBtn->setDisabled(true); }); // 7.將訊號和工作類物件中的任務函數連線 connect(this, &Widget::TellToConnect, working, &MyThread::connectToServer); // 8.將檔案路徑發給任務函數 connect(this, &Widget::SendToFile, working, &MyThread::SendFile); // 9.將傳送檔案按鈕設定成可用狀態 ui->sendBtn->setDisabled(true); } Widget::~Widget() { delete ui; } // 連線伺服器 void Widget::on_connectBtn_clicked() { // 獲取ip 和 埠號 QString ip = ui->ip_lineEide->text(); unsigned short port = ui->port_lineEdit->text().toShort(); // 將ip 和 埠號 傳送取出 emit this->TellToConnect(port, ip); // 將傳送檔案按鈕設定成不可用狀態 ui->sendBtn->setDisabled(false); } // 選中檔案 void Widget::on_selectBtn_clicked() { m_path = QFileDialog::getOpenFileName(); // 開啟檔案選擇對話方塊 // 判斷選中的對話方塊不能為空 if(m_path.isEmpty()) QMessageBox::warning(this, "警告", "選中要傳送的檔案不能為空"); // 將選中的檔案路徑顯示到單行編輯框中 ui->filePath_lineEdit->setText(m_path); } // 傳送檔案 void Widget::on_sendBtn_clicked() { // 將選中的檔案路徑傳送給任務類 emit this->SendToFile(m_path); }
程式執行結果:
以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支援it145.com。
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45