02 Qt发送文件和接收

借助上一篇文章的内容,在原有的TCP通讯的基础上,在服务端和客户端之间发送文件。

首先把在客户端加一个用于显示发送进度的进度条,在服务器端把原有的发送和关闭换为选择和发送,如下图所示
客户端
服务器端

在客户端连接服务器之后建立套接字,服务器便通过判断是否有建立套接字,然后才可以选择文件,在connect函数内写上

//成功连接后,才能按选择文件
ui->buttonFile->setEnabled(true);

之后我们在serverwidget.h中定义文件,文件名,文件大小等变量,在serverwidget.cpp中引用,在选择按钮中建立槽函数。

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() << "只读方式打开文件失败 77 ";
        }

        ui->buttonFile->setEnabled(false);
        ui->buttonSend->setEnabled(true);
    }
    else
    {
        qDebug() << "选择文件路径出错 62";
    }

之后便通过发送按钮进行发送,在槽函数内我们要记住要定义文件头,防止黏包,也起到加密作用,之后再20ms后启动定时器开始发送

void ServerWidget::on_buttonSend_clicked()
{
    //先发送文件头信息
    QString head=QString("%1##%2").arg(fileName).arg(fileSize);
    //发送头部信息
    qint64 len =tcpSocket->write(head.toUtf8());
    if(len>0)
    {
        //发送真正的文件信息
        //防止TCP黏包文件
        timer.start(20);

    }
    else
    {
        qDebug() << "头部信息发送失败 110";
        file.close();
        ui->buttonFile->setEnabled(true);
        ui->buttonSend->setEnabled(false);

    }
}

还有要特别注意发送必须要使用定时器,要不然发送会失败,我们在主函数connect函数下面添加定时器,还有在serverwidget.h中要定义变量QTimer timer;

connect(&timer,&QTimer::timeout,
            [=]()
    {
        //关闭定时器
        timer.stop();
        //发送文件
        sendData();
    });

这样发送文件便完成了,紧接着我们在服务端中对发送过来的文件进行判断是否接收完成,把接收完成的信息返回给服务器,告诉它我已经接收完成。
首先,我们定义一个标志位isstart,用于判断是否可以接收,开始接收后,标志位就置false,防止再次接收。然后我们要对接收到的数据处理,判断文件头是否就是我们服务端发送的文件头,是就开始接收。

if(true==isStart)
{   
    //接收头
    isStart=false;
    //解析头部信息buf="hello##1024"
    //                    QString str="hello##1024mike";
    //                    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() << "WritOnly error 40";
    }

    //弹出对话框,显示接收文件的大小
    QString str=QString("接收的文件: [%1:%2kb]").arg(fileName).arg(fileSize);
    QMessageBox::information(this,"文件信息",str);

    //设置进度条
    ui->progressBar->setMinimum(0);
    ui->progressBar->setMaximum(fileSize/1024);
    ui->progressBar->setValue(0);
}

接收完后,我们在下面写一个else,判断已经接收完成,给服务器发送信息

else //文件信息
{
    qint64 len =file.write(buf);
    if(len>0)
    {
          recvSize+=len;
          qDebug() <<len;
    }
    ui->progressBar->setValue(recvSize/1024);

    if(recvSize==fileSize)
    {

         QString str=QString::number(recvSize);

         //tcpSocket->write(str.toUtf8().data());
         tcpSocket->write("file done");

         file.close();
         QMessageBox::information(this,"完成","文件接收完成");

         tcpSocket->disconnectFromHost();
         tcpSocket->close();
     }
}

然后在服务器端写上判断是否客户端是否接收完成

connect(tcpSocket,&QTcpSocket::readyRead,
                [=]()
        {
            QByteArray buf=tcpSocket->readAll();
            if(QString(buf)=="file done")
            {
                //文件接收完毕
                ui->textEdit->append("接收完毕");
                file.close();


                //断开服务端端口
                tcpSocket->disconnectFromHost();
                tcpSocket->close();
            }
            else
            {
                qDebug() <<buf;
            }
        });

到这里就基本上完成了
这里写图片描述

以下是一个基于 Qt 的 UDP 线程实现发送接收文件的示例代码: ```cpp // 文件发送方的代码 class UdpSender : public QObject { Q_OBJECT public: UdpSender(QObject* parent = nullptr) : QObject(parent) {} public slots: void sendFile(const QString& filePath, const QHostAddress& address, quint16 port) { QFile file(filePath); if (!file.open(QIODevice::ReadOnly)) { qWarning() << "Failed to open file:" << filePath; return; } QUdpSocket socket; while (!file.atEnd()) { QByteArray data = file.read(8192); // 每次读取 8KB 数据 socket.writeDatagram(data, address, port); socket.waitForBytesWritten(); } qInfo() << "File sent successfully."; } }; // 文件接收方的代码 class UdpReceiver : public QObject { Q_OBJECT public: UdpReceiver(QObject* parent = nullptr) : QObject(parent) {} public slots: void receiveFile(const QString& filePath, quint16 port) { QFile file(filePath); if (!file.open(QIODevice::WriteOnly)) { qWarning() << "Failed to open file:" << filePath; return; } QUdpSocket socket; socket.bind(QHostAddress::AnyIPv4, port); while (socket.waitForReadyRead()) { while (socket.hasPendingDatagrams()) { QByteArray data; data.resize(socket.pendingDatagramSize()); socket.readDatagram(data.data(), data.size()); file.write(data); } } qInfo() << "File received successfully."; } }; ``` 在此示例中,`UdpSender` 类用于发送文件,`UdpReceiver` 类用于接收文件。其中,`UdpSender::sendFile()` 方法将文件分块读取并逐一发送,`UdpReceiver::receiveFile()` 方法则不断等待接收数据,直到收到完整的文件为止。 你可以在自己的代码中使用这些类来实现 UDP 文件传输功能。需要注意的是,由于 UDP 是无连接的协议,因此在发送接收数据需要确保数据的完整性和正确性。你可以通过添加一些校验码或者确认机制来实现这一点。
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值