QT實現(xiàn)文件傳輸功能
本文實例為大家分享了QT實現(xiàn)文件傳輸功能的具體代碼,供大家參考,具體內(nèi)容如下
過程如下:
1、服務器端設(shè)置監(jiān)聽套接字,開始監(jiān)聽;
2、客戶端在連接成功時開始傳送文件,有connected()信號連接send()槽,send()發(fā)送文件頭信息,包括文件名、文件總大小和文件名大小等;
3、傳送完文件頭信息時開始傳送文件內(nèi)容,有bytesWritten(qint64)信號連接到goOnSend(qint64)槽,前者是當想套接字寫入數(shù)據(jù)時會出發(fā)的信號,即當已經(jīng)想套接字寫入數(shù)據(jù),就繼續(xù)傳送數(shù)據(jù),有send()傳送文件頭信息開始觸發(fā),直到文件傳完為止。
4、在服務器端,首先接收文件頭信息,然后讀取文件名來用新建文件的方式打開一個文件,然后讀取文件名即文件等大小信息,用來更新進度條和繼續(xù)接收數(shù)據(jù);
5、實現(xiàn)循環(huán)傳輸,在客戶端,因為第一次send()是由connected()信號觸發(fā)的,之后的每次傳送應該手動調(diào)用send();在服務器端,在有新數(shù)據(jù)到達時,會判斷是否為頭文件,因此在每次文件傳完的時候?qū)yteReceived重置為0,即下一次再接收到數(shù)據(jù)的時候依據(jù)byteReceived判斷的結(jié)果就是一個新文件了。
客戶端代碼:
#ifndef WIDGET_H ? #define WIDGET_H ? ?? #include <QWidget> ? #include <QTcpSocket> ? #include <QFile> ? #include <string> ? ?? namespace Ui { ? class Widget; ? } ? ?? class Widget : public QWidget ? { ? ? ? Q_OBJECT ? ?? public: ? ? ? explicit Widget(QWidget *parent = 0); ? ? ? ~Widget(); ? ? ? ?? private: ? ? ? Ui::Widget *ui; ? ?? ? ? QTcpSocket *tcpClient; ? ? ? QFile *localFile; ? ? ? QString fileName; ?//文件名 ? ?? ? ? QByteArray outBlock; ?//分次傳 ? ? ? qint64 loadSize; ?//每次發(fā)送數(shù)據(jù)的大小 ? ? ? qint64 byteToWrite; ?//剩余數(shù)據(jù)大小 ? ? ? qint64 totalSize; ?//文件總大小 ? ?? ? ? int sendTimes; ?//用來標記是否為第一次發(fā)送,第一次以后連接信號觸發(fā),后面的則手動調(diào)用 ? ?? private slots: ? ? ? void send(); ?//傳送文件頭信息 ? ? ? void goOnSend(qint64); ?//傳送文件內(nèi)容 ? ? ? void on_openPushButton_clicked(); ? ? ? void on_sendPushButton_clicked(); ? }; ? ?? #endif // WIDGET_H ?
widget.cpp
#include "widget.h" ? #include "ui_widget.h" ? #include <QHostAddress> ? #include <QTextCodec> ? #include <QFileDialog> ? ?? Widget::Widget(QWidget *parent) : ? ? ? QWidget(parent), ? ? ? ui(new Ui::Widget) ? { ? ? ? ui->setupUi(this); ? ?? ? ? ui->progressLabel->hide(); ? ? ? QTextCodec::setCodecForLocale(QTextCodec::codecForName("UTF8")); ?? ? ? tcpClient = new QTcpSocket(this); ? ? ? sendTimes = 0; ? ?? ? ? connect(tcpClient, SIGNAL(connected()), this, SLOT(send())); ?//當連接成功時,就開始傳送文件 ? ? ? connect(tcpClient, SIGNAL(bytesWritten(qint64)), this, SLOT(goOnSend(qint64))); ?? } ? ?? void Widget::send() ?//發(fā)送文件頭信息 ? { ? ? ? byteToWrite = localFile->size(); ?//剩余數(shù)據(jù)的大小 ? ? ? totalSize = localFile->size(); ? ?? ? ? loadSize = 4*1024; ?//每次發(fā)送數(shù)據(jù)的大小 ? ?? ? ? QDataStream out(&outBlock, QIODevice::WriteOnly); ? ? ? QString currentFileName = fileName.right(fileName.size() - fileName.lastIndexOf('/')-1); ? ?? ? ? out<<qint64(0)<<qint64(0)<<currentFileName; ? ?? ? ? totalSize += outBlock.size(); ?//總大小為文件大小加上文件名等信息大小 ? ? ? byteToWrite += outBlock.size(); ? ?? ? ? out.device()->seek(0); ?//回到字節(jié)流起點來寫好前面連個qint64,分別為總大小和文件名等信息大小 ? ? ? out<<totalSize<<qint64(outBlock.size()); ? ?? ? ? tcpClient->write(outBlock); ?//將讀到的文件發(fā)送到套接字 ? ?? ? ? ui->progressLabel->show(); ? ? ? ui->sendProgressBar->setMaximum(totalSize); ? ? ? ui->sendProgressBar->setValue(totalSize - byteToWrite); ? } ? ?? void Widget::goOnSend(qint64 numBytes) ?//開始發(fā)送文件內(nèi)容 ? { ? ? ? byteToWrite -= numBytes; ?//剩余數(shù)據(jù)大小 ? ? ? outBlock = localFile->read(qMin(byteToWrite, loadSize)); ? ? ? tcpClient->write(outBlock); ? ?? ? ? ui->sendProgressBar->setMaximum(totalSize); ? ? ? ui->sendProgressBar->setValue(totalSize - byteToWrite); ? ?? ? ? if(byteToWrite == 0) ?//發(fā)送完畢 ? ? ? ? ? ui->sendStatusLabel->setText(tr("文件發(fā)送完畢!")); ? } ? ?? Widget::~Widget() ? { ? ? ? delete ui; ? } ? ?? void Widget::on_openPushButton_clicked() ?//打開文件并獲取文件名(包括路徑) ? { ? ? ? ui->sendStatusLabel->setText(tr("正在打開文件...")); ? ? ? ui->sendProgressBar->setValue(0); ?//非第一次發(fā)送 ? ?? ? ? loadSize = 0; ? ? ? byteToWrite = 0; ? ? ? totalSize = 0; ? ? ? outBlock.clear(); ? ?? ? ? fileName = QFileDialog::getOpenFileName(this); ? ? ? localFile = new QFile(fileName); ? ? ? localFile->open(QFile::ReadOnly); ? ?? ? ? ui->sendStatusLabel->setText(tr("已打開文件 %1").arg(fileName)); ? } ? ?? void Widget::on_sendPushButton_clicked() ? { ? ? ? if(sendTimes == 0) ?//只有第一次發(fā)送的時候,是發(fā)生在連接產(chǎn)生信號connect時 ? ? ? { ? ? ? ? ? tcpClient->connectToHost(QHostAddress("192.168.1.137"), 1000); ? ? ? ? ? sendTimes = 1; ? ? ? ? } ? ? ? else ? ? ? ? ? send(); ?//第一次發(fā)送的時候是由connectToHost出發(fā)connect信號才能調(diào)用send,第二次之后就需要調(diào)用send了 ? ?? ? ? ui->sendStatusLabel->setText(tr("正在發(fā)送文件 %1").arg(fileName)); ? } ?
服務端代碼:
widget.h
#ifndef WIDGET_H ? #define WIDGET_H ? ?? #include <QWidget> ? #include <QtNetwork/QTcpServer> ? #include <QtNetwork/QTcpSocket> ? #include <QFile> ? #include <QString> ? ?? namespace Ui { ? class Widget; ? } ? ?? class Widget : public QWidget ? { ? ? ? Q_OBJECT ? ? ? ?? public: ? ? ? explicit Widget(QWidget *parent = 0); ? ? ? ~Widget(); ? ? ? ?? private: ? ? ? Ui::Widget *ui; ? ?? ? ? QTcpServer *server; ? ? ? QTcpSocket *receivedSocket; ? ? ? QFile *newFile; ? ?? ? ? QByteArray inBlock; ? ? ? QString fileName; ? ? ? qint64 totalSize; ?//總共需要發(fā)送的文件大?。ㄎ募?nèi)容&文件名信息) ? ? ? qint64 byteReceived; ?//已經(jīng)發(fā)送的大小 ? ?? private slots: ? ? ? void acceptConnection(); ? ? ? void readClient(); ? ? ? void on_pushButton_clicked(); ? }; ? ?? #endif // WIDGET_H ?
widget.cpp
#include "widget.h" ? #include "ui_widget.h" ? #include <QTextCodec> ? ?? Widget::Widget(QWidget *parent) : ? ? ? QWidget(parent), ? ? ? ui(new Ui::Widget) ? { ? ? ? ui->setupUi(this); ? ? ? ui->progressLabel->hide(); ?? ? ? QTextCodec::setCodecForLocale(QTextCodec::codecForName("UTF8")); } ? ?? void Widget::acceptConnection() ? { ? ? ? ui->receivedStatusLabel->setText(tr("已連接,正在準備接收文件!")); ? ?? ? ? receivedSocket = server->nextPendingConnection(); ? ? ? connect(receivedSocket, SIGNAL(readyRead()), this, SLOT(readClient())); ? } ? ?? void Widget::readClient() ? { ? ? ? ui->receivedStatusLabel->setText(tr("正在接收文件...")); ? ?? ? ? if(byteReceived == 0) ?//才剛開始接收數(shù)據(jù),此數(shù)據(jù)為文件信息 ? ? ? { ? ? ? ? ? ui->receivedProgressBar->setValue(0); ? ?? ? ? ? ? QDataStream in(receivedSocket); ? ? ? ? ? in>>totalSize>>byteReceived>>fileName; ? ? ? ? ? ? newFile = new QFile(fileName); ? ? ? ? ? newFile->open(QFile::WriteOnly); ? ? ? } ? ? ? else ?//正式讀取文件內(nèi)容 ? ? ? { ? ? ? ? ? inBlock = receivedSocket->readAll(); ? ?? ? ? ? ? byteReceived += inBlock.size(); ? ? ? ? ? newFile->write(inBlock); ? ? ? ? ? newFile->flush(); ? ? ? } ?? ? ? ui->progressLabel->show(); ? ? ? ui->receivedProgressBar->setMaximum(totalSize); ? ? ? ui->receivedProgressBar->setValue(byteReceived); ? ?? ? ? if(byteReceived == totalSize) ? ? ? { ? ? ? ? ? ui->receivedStatusLabel->setText(tr("%1接收完成").arg(fileName)); ? ?? ? ? ? ? inBlock.clear(); ? ? ? ? ? byteReceived = 0; ? ? ? ? ? totalSize = 0; ? ? ? } ? } ? ?? Widget::~Widget() ? { ? ? ? delete ui; ? } ?? void Widget::on_pushButton_clicked() ? { ? ? ? totalSize = 0; ? ? ? byteReceived = 0; ? ?? ? ? server = new QTcpServer(this); ? ? ? server->listen(QHostAddress("192.168.1.137"), 1000); ? ?? ? ? connect(server, SIGNAL(newConnection()), this, SLOT(acceptConnection())); ? ?? ? ? ui->receivedProgressBar->setValue(0); ? ? ? ui->receivedStatusLabel->setText(tr("開始監(jiān)聽...")); ? }?
以上就是本文的全部內(nèi)容,希望對大家的學習有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
使用C++實現(xiàn)MySQL數(shù)據(jù)庫連接池
這篇文章主要為大家詳細介紹了如何使用C++實現(xiàn)MySQL數(shù)據(jù)庫連接池,文中的示例代碼講解詳細,具有一定的借鑒價值,有需要的小伙伴可以了解下2024-03-03C++簡明圖解分析靜態(tài)成員與單例設(shè)計模式
與靜態(tài)數(shù)據(jù)成員不同,靜態(tài)成員函數(shù)的作用不是為了對象之間的溝通,而是為了能處理靜態(tài)數(shù)據(jù)成員,靜態(tài)成員函數(shù)沒有this指針。既然它沒有指向某一對象,也就無法對一個對象中的非靜態(tài)成員進行默認訪問2022-06-06C++實現(xiàn)LeetCode(92.倒置鏈表之二)
這篇文章主要介紹了C++實現(xiàn)LeetCode(倒置鏈表之二),本篇文章通過簡要的案例,講解了該項技術(shù)的了解與使用,以下就是詳細內(nèi)容,需要的朋友可以參考下2021-07-07數(shù)據(jù)結(jié)構(gòu) 棧的操作實例詳解
這篇文章主要介紹了數(shù)據(jù)結(jié)構(gòu) 順序棧的定義、初始化、空棧判斷、入棧、出棧操作的相關(guān)資料,需要的朋友可以參考下2017-06-06解析C++編程中virtual聲明的虛函數(shù)以及單個繼承
這篇文章主要介紹了C++編程中virtual聲明的虛函數(shù)以及單個繼承,剖析虛函數(shù)和單個基類所能夠繼承的成員,要的朋友可以參考下2016-01-01