TCP傳文件流程圖:
工程目錄:
clientwidget.h:
#ifndef CLIENTWIDGET_H #define CLIENTWIDGET_H #include <QWidget> #include <QTcpSocket> #include <QFile> namespace Ui { class ClientWidget; } class ClientWidget : public QWidget { Q_OBJECT public: explicit ClientWidget(QWidget *parent = 0); ~ClientWidget(); private slots: void on_buttonConnect_clicked(); private: Ui::ClientWidget *ui; QTcpSocket *tcpSocket; QFile file;//文件對象 QString fileName;//文件名字 qint64 fileSize;//文件大小 qint64 recvSize;//已經接收文件的大小 bool isStart;//接收頭文件標志 }; #endif // CLIENTWIDGET_H
serverwidget.h:
#ifndef SERVERWIDGET_H #define SERVERWIDGET_H #include <QWidget> #include <QTcpServer>//監聽套接字 #include <QTcpSocket>//通信套接字 #include <QFile> #include <QTimer> namespace Ui { class serverWidget; } class serverWidget : public QWidget { Q_OBJECT public: explicit serverWidget(QWidget *parent = 0); ~serverWidget(); void sendData();//發送文件數據 private slots: void on_buttonFile_clicked(); void on_buttonsend_clicked(); private: Ui::serverWidget *ui; QTcpServer *tcpServer;//監聽套接字 QTcpSocket *tcpSocket;//通信套接字 QFile file;//文件對象 QString fileName;//文件名字 qint64 fileSize;//文件大小 qint64 sendSize;//已經發送文件的大小 QTimer timer;//定時器 }; #endif // SERVERWIDGET_H
clientwidget.cpp:
#include "clientwidget.h" #include "ui_clientwidget.h" #include <QDebug> #include <QMessageBox> #include <QHostAddress> ClientWidget::ClientWidget(QWidget *parent) : QWidget(parent), ui(new Ui::ClientWidget) { ui->setupUi(this); tcpSocket = new QTcpSocket(this); isStart = true; //設置進度條 ui->progressBar->setValue(0);//當前值 connect(tcpSocket,&QTcpSocket::readyRead,[=](){ //取出接收的內容 QByteArray buf = tcpSocket->readAll(); if (true == isStart) { //接收頭 isStart = false; // 分段 0 0 1 1 2 2 //解析頭部信息 buf = "hello##1024##333333" // QString str = "hello##1024"; // str.section("##",0,0);//這個拆出來hello,其中##是分段標識符,格式為:段1+標識符+段2+標識符+段3+標識符+…… //初始化 fileName = QString(buf).section("##",0,0); fileSize = QString(buf).section("##",1,1).toInt(); recvSize = 0; //打開文件 file.setFileName(fileName); bool isOk = file.open(QIODevice::WriteOnly); if (false == isOk) { qDebug()<<"WriteOnly error 38 "; tcpSocket->disconnectFromHost();//斷開連接 tcpSocket->close();//關閉套接字 return ;//如果打開文件失敗,中斷函數 } //彈出對話框,顯示接收文件信息 QString str =QString("接收文件: [%1 : %2kb]").arg(fileName).arg(fileSize/1024); QMessageBox::information(this,"文件信息",str); //設置進度條 ui->progressBar->setMinimum(0);//最小值 ui->progressBar->setMaximum(fileSize/1024);//最大值 ui->progressBar->setValue(0);//當前值 } else//文件信息 { qint64 len = file.write(buf); if(len > 0) { recvSize += len;//累積接收大小 qDebug()<<len; } //更新進度條 ui->progressBar->setValue(recvSize/1024); if (recvSize == fileSize) { //先給服務發送(接收文件完成的消息) tcpSocket->write("file done "); QMessageBox::information(this,"完成","文件接收完畢"); file.close();//關閉文件 //斷開連接 tcpSocket->disconnectFromHost(); tcpSocket->close(); } } }); } ClientWidget::~ClientWidget() { delete ui; } void ClientWidget::on_buttonConnect_clicked() { //獲取服務器的ip和端口 QString ip = ui->lineEditIP->text(); qint16 port = ui->lineEditPort->text().toInt(); tcpSocket->connectToHost(QHostAddress(ip),port); }
main.cpp:
#include "serverwidget.h" #include <QApplication> #include "clientwidget.h" int main(int argc, char *argv[]) { QApplication a(argc, argv); serverWidget w; w.show(); ClientWidget w2; w2.show(); return a.exec(); }
serverwidget.cpp:
#include "serverwidget.h" #include "ui_serverwidget.h" #include <QFileDialog> #include <QDebug> serverWidget::serverWidget(QWidget *parent) : QWidget(parent), ui(new Ui::serverWidget) { ui->setupUi(this); //監聽套接字 tcpServer = new QTcpServer(this); //監聽 tcpServer->listen(QHostAddress::Any,8888); setWindowTitle("服務器端口為:8888"); //兩個按鈕都不能按 ui->buttonFile->setEnabled(false); ui->buttonsend->setEnabled(false); //如果客戶端成功和服務器連接 //tcpServer 會自動觸發 newConnection() connect(tcpServer,&QTcpServer::newConnection,[=](){ //取出建立好連接的套接字 tcpSocket = tcpServer->nextPendingConnection(); //獲取對方的ip和端口 QString ip = tcpSocket->peerAddress().toString(); quint16 port = tcpSocket->peerPort(); QString str = QString("[%1 : %2] 成功連接").arg(ip).arg(port); //顯示到編輯區 ui->textEdit->setText(str); //成功連接后,才能按兩個按鈕 ui->buttonFile->setEnabled(true); ui->buttonsend->setEnabled(true); connect(tcpSocket,&QTcpSocket::readyRead,[=](){ //取客戶端信息 QByteArray buf = tcpSocket->readAll(); if (QString(buf) == "file done") { //文件接收完畢 ui->textEdit->append("文件發送完畢"); file.close(); //斷開客戶端端口 tcpSocket->disconnectFromHost(); tcpSocket->close(); } }); }); connect(&timer,&QTimer::timeout,[=](){ //關閉定時器 timer.stop(); //發送文件 sendData(); }); } serverWidget::~serverWidget() { delete ui; } //選擇文件按鈕 void serverWidget::on_buttonFile_clicked() { QString filePath = QFileDialog ::getOpenFileName(this,"open","../"); if (false == filePath.isEmpty()) { fileName.clear(); fileSize = 0; //獲取文件信息 QFileInfo info(filePath); fileName = info.fileName();//獲取文件名字 fileSize = info.size();//獲取文件大小 sendSize = 0;//發送文件的大小 //只讀方式打開文件 //指定文件的名字 file.setFileName(filePath); //打開文件 bool isOk = file.open(QIODevice::ReadOnly); if (false == isOk) { qDebug()<<"只讀方式打開文件失敗 78"; } //提示打開文件路徑 ui->textEdit->append(filePath); ui->buttonFile->setEnabled(false); ui->buttonsend->setEnabled(true); } else { qDebug()<<"選擇文件路徑出錯 62 "; } } //發送文件按鈕按鍵 void serverWidget::on_buttonsend_clicked() { //先發送文件頭信息 格式如:文件名##文件大小 QString head = QString("%1##%2").arg(fileName).arg(fileSize); //發送頭部的信息 qint64 len = tcpSocket->write(head.toUtf8()); if (len > 0)//頭部信息發送成功 { //發送真正的文件信息 //防止TCP黏包文件 //需要通過定時器延時 20ms timer.start(20); } else { qDebug()<<"頭部信息發送失敗 114"; file.close(); ui->buttonFile->setEnabled(true); ui->buttonsend->setEnabled(false); } } void serverWidget::sendData() { qint64 len = 0; do { //每次發送數據的大小 4K char buf[4*1024] = {0}; len = 0; //往文件中讀數據 len = file.read(buf,sizeof(buf)); //發送數據,讀多少 ,發多少 len = tcpSocket->write(buf,len); //發送的數據需要積累 sendSize += len; } while(len > 0); //是否發送文件完畢 if(sendSize == fileSize) { ui->textEdit->append("文件發送完畢"); file.close(); //把客戶端關閉 tcpSocket->disconnectFromHost(); tcpSocket->close(); } }
clientwidget.ui:
serverwidget.ui: