TCPFile
tcp協議傳輸文件
TCPFile.pro
QT += core gui network
clientwidget.h
#include <QWidget>
#include <QTcpSocket> // 通信套接字
#include <QFile>private slots:void on_pushButton_clicked();private:QTcpSocket *tcpSocket;QFile file; // 文件對象QString fileName; // 文件名字qint64 fileSize; // 文件大小qint64 recvSize; // 已經接收文件的大小bool isStart; // 標志位
widget.h
#include <QTcpServer> // 監聽套接字
#include <QTcpSocket> // 通信套接字
#include <QFile>
#include <QTimer>public:void sendData(); // 發送文件數據private slots:void on_pushButton_clicked();void on_pushButton_2_clicked();private:QTcpServer *tcpServer;QTcpSocket *tcpSocket;QFile file; // 文件對象QString fileName; // 文件名字qint64 fileSize; // 文件大小qint64 sendSize; // 已經發送文件的大小QTimer timer; // 定時器
clientwidget.cpp
#include <QDebug>
#include <QMessageBox>
#include <QHostAddress>Clientwidget::Clientwidget(QWidget *parent) :QWidget(parent),ui(new Ui::Clientwidget)
{ui->setupUi(this);isStart = true;tcpSocket = NULL;// 分配空間,指定父對象tcpSocket = new QTcpSocket(this);setWindowTitle("客戶端");// 進度條ui->progressBar->setValue(0); // 當前值connect(tcpSocket, &QTcpSocket::readyRead, [=](){// 取出接收內容QByteArray buf = tcpSocket->readAll();if(true == isStart){ // 接收頭信息isStart = false;// 解析頭部信息 舉例:// QString str = "hello##1024";// str.section("##", 0, 0);// 初始化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";}// 設置進度條ui->progressBar->setMinimum(0); // 最小值ui->progressBar->setMaximum(fileSize/1024); // 最大值ui->progressBar->setValue(0); // 當前值}else { // 文件信息qint64 len = file.write(buf);if(len > 0){ // 接收數據大于0recvSize += len; // 累加接收大小qDebug() << len;}ui->progressBar->setValue(recvSize/1024); // 更新進度條if(recvSize == fileSize){ // 文件接收完畢file.close();QMessageBox::information(this, "完成", "文件接收完成");// 給服務器發送 接收文件完成的信息tcpSocket->write("file done");tcpSocket->disconnectFromHost();tcpSocket->close();}}});}void Clientwidget::on_pushButton_clicked()
{// 獲取服務器ip和端口QString ip = ui->lineEdit->text();quint16 port = ui->lineEdit_2->text().toInt();// 主動和服務器建立連接tcpSocket->connectToHost(QHostAddress(ip), port);
}
widget.cpp
#include <QFileDialog>
#include <QDebug>
#include <QFileInfo>Widget::Widget(QWidget *parent) :QWidget(parent),ui(new Ui::Widget)
{ui->setupUi(this);// 監聽套接字tcpServer = new QTcpServer(this);// 監聽tcpServer->listen(QHostAddress::AnyIPv4, 8888);setWindowTitle("服務器 端口8888");// 一開始兩個按鈕都不能按 需要建立連接后才可以按下ui->pushButton->setEnabled(false);ui->pushButton_2->setEnabled(false);// 如果客戶端成功和服務器連接// tcpServer 會自動觸發 newConnection()connect(tcpServer, &QTcpServer::newConnection, [=](){// 取出建立好連接的套接字tcpSocket = tcpServer->nextPendingConnection();// 獲取對方的ip和端口QString ip = tcpSocket->peerAddress().toString();quint16 port = tcpSocket->peerPort();// qDebug() << port;QString temp = QString("[%1:%2]:成功連接").arg(ip).arg(port);ui->textEdit->setText(temp); // 顯示到編輯區// 成功建立連接后,才可以按鈕 選擇文件ui->pushButton->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();});}Widget::~Widget()
{delete ui;
}void Widget::sendData()
{qint64 len = 0;do{// 每次發送數據的大小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();ui->pushButton->setEnabled(false);ui->pushButton_2->setEnabled(false);}
}// 選擇文件按鈕
void Widget::on_pushButton_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() << "只讀方式打開文件失敗";}// 提示打開文件的路徑ui->textEdit->append(filePath);ui->pushButton->setEnabled(false);ui->pushButton_2->setEnabled(true);}else{qDebug() << "選擇文件路徑出錯";}
}// 發送文件按鈕
void Widget::on_pushButton_2_clicked()
{// 先發送文件頭信息 文件名##文件大小QString head = QString("%1##%2").arg(fileName).arg(fileSize);// 發送頭部信息qint64 len = tcpSocket->write( head.toUtf8() );if(len > 0) { // 頭部信息發送成功// 發送真正的文件信息// 防止TCP黏包問題 需要通過定時器延時 20mstimer.start(20);}else {qDebug() << "頭部信息發送失敗";file.close();ui->pushButton->setEnabled(true);ui->pushButton_2->setEnabled(false);}
}
clientwidget.ui
widget.ui