QT中TCP文件传输


*免责声明:
1、视频来源于传智播客
2、此方法仅提供参考

本文代码根据B站《零基础入门六天学会QT完整版》中的P52和P53,其中视频有缺失,为了造福其他兄弟,在此补上缺失代码


首先需要创建两个类:ServerWidget和ClientWidget类

一、UI文件

1.serverwidget.ui

在这里插入图片描述

2.clientwidget.ui

在这里插入图片描述

二、.h文件

1.serverwidget.h

在这里插入图片描述

2.clientwidget.h

在这里插入图片描述

三、cpp文件

1.ClientWidget.cpp

#include "clientwidget.h"
#include "ui_clientwidget.h"
#include <QMessageBox>
#include <QHostAddress>
#include <QDebug>

ClientWidget::ClientWidget(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::ClientWidget)
{
    ui->setupUi(this);

    //创建TCP套接字
    tcpSocket = new QTcpSocket(this);

    //设置标题
    setWindowTitle("客户端");

    //如果连接成功
    connect(tcpSocket,&QTcpSocket::connected,
            [=]()
    {
       //初始化数据
        fileName = "";
        fileSize = 0;
        recvSize = 0;
        isFile = false;

        ui->buttonConnect->setEnabled(false);
        ui->textEdit->clear();

        ui->textEdit->append("和服务器连接成功");
    });

    ui->progressBar->setValue(0);

    //当有数据可接收时
    connect(tcpSocket,&QTcpSocket::readyRead,
            [=]()
    {
        QByteArray buf = tcpSocket->readAll();  //一次收8k

        if(false == isFile)//先接受头部信息(第一条数据)
        {
            isFile = true;
            //head # filename # size
            //文件名称
            fileName = QString(buf).section("#",1,1);
            //文件大小
            fileSize = QString(buf).section("#",2,2).toInt();
            qDebug() << fileName << fileSize;

            recvSize = 0;

            file.setFileName(fileName);

            if(false == file.open(QIODevice::WriteOnly)){
                //初始化数据
                fileName = "";
                fileSize = 0;
                recvSize = 0;
                isFile = false;
                QMessageBox::warning(this,"警告","创建文件失败");
                return;
            }

            //设置进度条最大值最小值
            ui->progressBar->setMinimum(0);
            ui->progressBar->setMaximum(fileSize/1024);

            ui->textEdit->append(QString("正在接受文件:\n%1").arg(fileName));

        }

        else//文件数据!!!
        {
            qint64 len = file.write(buf);
            recvSize += len;
            qDebug() << len;
            ui->progressBar->setValue(recvSize/1024);

        }

        if (recvSize == fileSize)
        {
           file.close();  //接收完毕后要记得关闭文件
           ui->buttonConnect->setEnabled(true);
           tcpSocket->disconnectFromHost();  //手动断开连接

           QMessageBox::information(this,"ok","文件接受完毕");
           ui->textEdit->append("文件接受完毕");

        }
    });
}

ClientWidget::~ClientWidget()
{
    delete ui;
}

//连接按钮
void ClientWidget::on_buttonConnect_clicked()
{
    ui->progressBar->setValue(0);//设置进度条0

    //初始化操作
    QString ip = ui->lineEditIP->text();
    qint16 port = ui->lineEditPort->text().toInt();
    if(ip.isEmpty() == true || port == 0)
    {
        QMessageBox::warning(this,"警告","ip或端口不能为空");
        return;
    }

    tcpSocket->abort();//取消已有的连接

    //连接服务器!
    tcpSocket->connectToHost(QHostAddress(ip),port);
}

2.ServerWidget.cpp

#include "serverwidget.h"
#include "ui_serverwidget.h"
#include <QFile>
#include <QFileDialog>
#include <QMessageBox>
#include <QTimer>
#include <QThread>

ServerWidget::ServerWidget(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::ServerWidget)
{
    ui->setupUi(this);

    //创建套接字
    tcpServer = new QTcpServer(this);

    //监听,端口:8888
    bool isOk = tcpServer->listen(QHostAddress::Any,8888);
    if(false == isOk)//监听失败
    {
        QMessageBox::warning(this,"监听","监听失败");
        return;
    }

    //设置标题
    setWindowTitle("服务器:88888");

    //设置按钮(变灰)
    ui->buttonChoose->setEnabled(false);
    ui->buttonSend->setEnabled(false);

    //当有客户端连接时,触发信号:newConnection
    connect(tcpServer,&QTcpServer::newConnection,
            [=]()
            {
                //接收客户端套接字对象,从连接请求中选择一个请求连接(取出套接字)
                tcpSocket = tcpServer->nextPendingConnection();

                //获取对方的ip和port
                QString ip = tcpSocket-> peerAddress().toString();//获取client的ip地址
                quint16 port = tcpSocket->peerPort();//获取client的端口号
                QString str = QString("[%1:%2]和服务器连接成功").arg(ip).arg(port);
                ui->textEdit->setText(str);//设置内容

                //恢复选择按钮状态
                ui->buttonChoose->setEnabled(true);
                QMessageBox::information(this,"允许","连接成功,可以选择文件发送");
            });

    //定时器处理函数
    connect(&timer,&QTimer::timeout,
            [=]()
    {
        this->timer.stop();//关闭定时器
        senFileData();
    });
}


ServerWidget::~ServerWidget()
{
    delete ui;
}



//选择文件按钮
void ServerWidget::on_buttonChoose_clicked()
{
    QString path = QFileDialog::getOpenFileName(this,"请选择所要发送的文件","../");
    if(path.isEmpty() == false)
    {
            file.setFileName(path);
            //只读方式打开文件
            bool isOk = file.open(QIODevice::ReadOnly);
            if(false == isOk)//打开文件失败
            {
                QMessageBox::warning(this,"警告","打开文件失败");
                return;
            }
            else
            {
                ui->textEdit->append("发送的文件:");
                ui->textEdit->append(path);

                //初始化数据
                fileName = "";
                fileSize = 0;
                sendSize = 0;

                //获取发送文件的信息
                QFileInfo info(path);
                fileName = info.fileName();
                fileSize = info.size();

                ui->buttonSend->setEnabled(true);//恢复发送文件按钮
                ui->buttonChoose->setEnabled(false);//选择按钮变灰

            }

    }
}

//发送文件按钮
void ServerWidget::on_buttonSend_clicked()
{
    //发送文件按钮变灰
    ui->buttonSend->setEnabled(false);

    //先发送文件头,自定义的数据,不是文件数据
    //先发送头。自定义组包, 文件名#文件大小
    QString buf = QString("head#%1#%2").arg(fileName).arg(fileSize);

    //先发头
    qint64 len = tcpSocket->write(buf.toUtf8().data());
    tcpSocket->waitForBytesWritten();//等待数据发送完毕

    ui->textEdit->append("已经在发送文件!!");

    if(len>0)//如果头部信息发送成功,开始发送文件数据
    {
        //10毫秒后在发送文件数据
        //启动定时器,定时器内容发送文件数据
        //防止tcp黏包问题
        this->timer.start(1000);//为了延时
    }
    else
    {
        file.close();
    }

}

void ServerWidget::senFileData(){

    //发送文件信息
    //发送文件
    qint64 len = 0 ;

    do{
        //每次发送2kb大小的数据,如果剩余的数据不足2kb,就发送剩余数据的大小
        char buf[2*1024]= {0};

        len = 0;
        len=file.read(  buf , sizeof(buf) );        //读数据
        len=tcpSocket->write(buf , len);            //发数据

        //发送数据需要累积
        sendSize += len;

    }while(len>0 );
    //文件数据发送完毕
    if (fileSize == sendSize)
        {
        //QMessageBox::information(this,"ok","文件发送完毕");
        ui->textEdit->append("发送成功");

        file.close();//关闭文件
        //关闭客户端
        tcpSocket->disconnectFromHost();
        tcpSocket->close();
    }
}

3.main.cpp

在这里插入图片描述


四、运行效果图

在这里插入图片描述

以上就是视频中TCP文件传输的代码,若有发现错误可以评论指出。

评论 13
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值