qt客户端与服务端关于传输文件

发布于:2024-08-15 ⋅ 阅读:(145) ⋅ 点赞:(0)

如果直接发 发送的数据永远要比接受的块 需要有时间间隔 此时定时器的作用就显现出来了

发送数据都先发头,要保证服务器发送的头,客户端能接受到

发送数据后不要直接读数据,加一个延迟

这里以##作为分隔符

发送多少读多少,

发送数据的操作

QT网络编程中关于发送文件的操作函数  规则就是从文件中读取多少就发送多少
void ServerWidget::senddata()
{

    qint64 len =0;
    do
    {
        //每次读4k的内容
        char buf[4*1024] ={0};
    len =  file.read(buf,sizeof(buf));  //read函数返回值为qint64
    //读多少发多少
    len =socket->write(buf,len); //统计的发送数据

    sendsize+=len;
//累积的文件大小
    }while(len>0);

    //判断文件发送完毕和总的文件作比较即可
    if(sendsize==filesize)
    {
        //提示用户
        ui->textEdit->append("文件已发送完毕");
        file.close();
        //发送完毕后断开连接 ,以免丢包
//建立好的通讯套接字断开连接
        socket->disconnectFromHost();
        socket->close();
    }
}

这个函数调用前需要有定时器的相关操作

需要先激活定时器 先发送头  间隔20ms发送

void ServerWidget::on_butsend_clicked()
{
    //发送文件头信息
    QString head = QString("%1##%2").arg(filename).arg(filesize);
    qint64 len =    socket->write(head.toUtf8()); // write函数返回值为qint64
    if(len>0)
    {
        // qDebug()<<"发送成功";
        timer->start(20);

    }else
    {
        qDebug()<<"发送信息失败";
        file.close();
        ui->butselect->setEnabled(1);
        ui->butselect->setEnabled(0);
    }


}

在选择按钮的函数中调用connect()关联信号和槽

void ServerWidget::on_butselect_clicked()
{
    // QString getOpenFileName(QWidget *parent = nullptr, const QString &caption = QString(), const QString &dir = QString(), const QString &filter = QString(), QString *selectedFilter
    QString path = QFileDialog::getOpenFileName(this,"打开文件","../");
    if(path.isEmpty()==false)
    {
        //路径不为空的话就打开该文件
        //每次选择文件的时候将文件名和大小清空
        filename.clear();
        filesize =0;
        QFileInfo info(path);

        //QFileInfo中有文件信息的成员函数
        // file.open();
        filename = info.fileName(); //获取文件名字
        filesize = info.size();//获取文件大小

        //用变量来标记文件发送了多少  防止丢包

        sendsize =0 ;
        //指定文件名字,只读方式打开文件按

        file.setFileName(path);

        if(!file.open(QIODevice::ReadOnly))
        {
            qDebug()<<"只读方式打开文件失败"<<'\n';
        }


        //提示用户打开文件的路径
        ui->textEdit->append(path);
        ui->butselect->setEnabled(false);

        ui->butselect->setEnabled(true);


    }else
    {
        qDebug()<<"选择文件无效"<<'\n';
    }

    connect(timer,&QTimer::timeout,[=](){

        timer->stop();
        senddata();
    });
}

客户端:

#include "clientwidget.h"
#include "ui_clientwidget.h"
#include <QMessageBox>
#include <QHostAddress>
Clientwidget::Clientwidget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Clientwidget)
{
    ui->setupUi(this);
    setWindowTitle("客户端");
    //ui->progressBar->setValue(0);//设置进度条的值
    isstart = true;
    csocket = new QTcpSocket(this);


    connect(csocket,&QTcpSocket::readyRead,[=](){

        QByteArray buf = csocket->readAll();
        if(true==isstart)
        {
            isstart = false;
            //初始化
            filename = QString(buf).section("##",0,0);
            filesize = QString(buf).section("##",1,1).toInt();
            recivesize =0;
            //打开文件

            file.setFileName(filename);
            bool isok = file.open(QIODevice::WriteOnly);
            if(false ==isok)
            {
                qDebug()<<"write only errno 29";
            }
            QString str = QString("接受的文件:[%1:%2kb]").arg(filename).arg(filesize/1024);

            QMessageBox::information(this,"文件信息",str);

            ui->progressBar->setMinimum(0);
            ui->progressBar->setMaximum(100);
            ui->progressBar->setValue(0);

        }
        else
        {
            qint64 len = file.write(buf);
            if(len>0)
            {
                 recivesize+=len;
                QString str = QString::number(recivesize);
                 csocket->write(str.toUtf8().data());
                //qDebug()<<len;
            }
            ui->progressBar->setValue(recivesize/1024);

            if(recivesize==filesize)
            {
                csocket->write("file done");
           QMessageBox::information(this,"提示","文件接受完成");
                file.close();


                csocket->disconnectFromHost();
                csocket->close();
                return ;
            }
        }
    });



    /*
String::section() 是 Qt 中 QString 类的一个成员函数,用于从字符串中提取指定范围内的子字符串。它可以根据分隔符或索引位置来提取子字符串。

QString::section() 函数签名
QString section(QChar sep, int startIndex, int endIndex, QString::SectionFlags flags = KeepEmptyParts) const;

参数说明
sep:分隔符,用于分割字符串。
startIndex:起始索引,表示从第几个分隔符开始提取。
endIndex:结束索引,表示到第几个分隔符结束提取。
flags:标志位,控制如何处理空的部分,默认为 KeepEmptyParts。
返回值
返回一个 QString,包含了从 startIndex 到 endIndex 之间的子字符串。
        */
}

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

void Clientwidget::on_butconnect_clicked()
{
    QString ip = ui->ipedit->text();

    quint64 port = ui->portedit->text().toInt();
    csocket->connectToHost(QHostAddress(ip),port);
}




网站公告

今日签到

点亮在社区的每一天
去签到