Qt详解实现TCP文件传输例子(文件下载和上传)附源码

这篇具有很好参考价值的文章主要介绍了Qt详解实现TCP文件传输例子(文件下载和上传)附源码。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

网络通信我们用的很频繁,如文字,语音,文件,图片等,这个些传输方式都差不多

QT文件传输主要考验对传输的控制,还是需要点逻辑的,文件传输的大致框架如下

qt tcp 发送文件,Qt开发,tcp/ip,网络,网络协议,文件传输

先看一下简单例子实现的效果(界面有点丑,重点在于内容):

qt tcp 发送文件,Qt开发,tcp/ip,网络,网络协议,文件传输

 接下来重点讲一下需要用到哪些东西:

1.数据流 QDataStream

通过数据流可以操作各种数据类型,包括类对象,存储到文件中数据可以还原到内存,对QDataStream不懂的,可以去看下我写的这个:QDataStream中 << 和 >> 输入输出重载的理解_qdatastream <<_只是个~小不点的博客-CSDN博客

在这个例子中用来封装传输消息类型,文件名,文件大小等数据

2. QTcpSocket QTcpServer

QTcpServer当服务器,QTcpSocket当客户端用,用来作为文件传输对象

3.一个服务器和一个客户端(这个例子目前仅支持单向连接),先从简单的一对一开始理解,扩展到一对多,多对多就容易点了

服务端界面如下:

qt tcp 发送文件,Qt开发,tcp/ip,网络,网络协议,文件传输

需要一个自定义一个文件对象,存在下载的文件信息:如文件名,文件大小,已经接收的字节数等,如下所示

qt tcp 发送文件,Qt开发,tcp/ip,网络,网络协议,文件传输

 接下来先将服务端的

定义一个枚举的消息类型,判断客户端想要哪些信息,文件信息还是文件数据

//消息类型
enum MsgType{
    FileInfo,   //文件信息,如文件名,文件大小等信息
    FileData,   //文件数据,即文件内容
};

先看下流程:

服务端接收到客户端连接后,监听客户端消息,如果收到客户端发送接收的消息类型是FileInfo,就发送文件信息给它。收到客户端发送接收的消息类型是FileData,就发送文件数据给它。

qt tcp 发送文件,Qt开发,tcp/ip,网络,网络协议,文件传输

传输文件信息时,需要获取要发送的文件信息,如文件名,文件大小等,然后将这些信息发送给客户端。客户端处理存储这些信息即可,接收文件数据的时候需要用到

 具体实现如下

void FileServer::transferFileInfo(QTcpSocket *socket)
{
    //获取文件数据,准备发送
    QByteArray  DataInfoBlock = getFileContent(ui->fileEdit->text());

    QThread::msleep(10); //添加延时
    m_fileInfoWriteBytes = socket->write(DataInfoBlock) - typeMsgSize;
    qDebug()<< "传输文件信息,大小:"<< m_sendFileSize;
    //等待发送完成,才能继续下次发送,否则发送过快,对方无法接收
    if(!socket->waitForBytesWritten(10*1000)) {
        ui->textBrowser->append(QString("网络请求超时,原因:%1").arg(socket->errorString()));
        return;
    }

    ui->textBrowser->append(QString("文件信息发送完成,开始对[%1]进行文件传输------------------")
                        .arg(socket->localAddress().toString()));
    qDebug()<<"当前文件传输线程id:"<<QThread::currentThreadId();

    m_localFile.setFileName(m_sendFilePath);
    if(!m_localFile.open(QFile::ReadOnly)){
        ui->textBrowser->append(QString("文件[%1]打开失败!").arg(m_sendFilePath));
        return;
    }
}

QByteArray FileServer::getFileContent(QString filePath)
{
    if(!QFile::exists(filePath)) {
        ui->textBrowser->append(QString("没有要传输的文件!" + filePath));
        return "";
    }
    m_sendFilePath = filePath;
    ui->textBrowser->append(QString("正在获取文件信息[%1]......").arg(filePath));
    QFileInfo info(filePath);

    //获取要发送的文件大小
    m_sendFileSize = info.size();

    ui->textBrowser->append(QString("要发送的文件大小:%1字节,%2M").arg(m_sendFileSize).arg(m_sendFileSize/1024/1024.0));

    //获取发送的文件名
    QString currentFileName=filePath.right(filePath.size()-filePath.lastIndexOf('/')-1);
    QByteArray DataInfoBlock;

    QDataStream sendOut(&DataInfoBlock,QIODevice::WriteOnly);
    sendOut.setVersion(QDataStream::Qt_5_12);
    int type = MsgType::FileInfo;
    //封装发送的信息到DataInfoBlock中
    sendOut<<int(type)<<QString(currentFileName)<<qint64(m_sendFileSize);

    ui->textBrowser->append(QString("文件[%1]信息获取完成!").arg(currentFileName));
    //发送的文件总大小中,信息类型不计入
    QString msg;
    if(m_sendFileSize>1024*1024) {
        msg = QString("%1M").arg(m_sendFileSize/1024/1024.0);
    }
    else {
        msg = QString("%1KB").arg(m_sendFileSize/1024.0);
    }
    ui->textBrowser->append(QString("发送的文件名:%1,文件大小:%2").arg(currentFileName).arg(msg));

    return DataInfoBlock;
}

关键在于发送的序列信息封装,依次为:

    QByteArray DataInfoBlock;

    QDataStream sendOut(&DataInfoBlock,QIODevice::WriteOnly);
    sendOut.setVersion(QDataStream::Qt_5_12);
    int type = MsgType::FileInfo;
    //封装发送的信息到DataInfoBlock中
        //消息类型             文件名                  //文件大小
    sendOut<<int(type)<<QString(currentFileName)<<qint64(m_sendFileSize);

发送给客户端即可,客户端解析的时候也是按照这个顺序依次解析

发送给客户端后,等待客户端的下一步指令即可。客户端接收到文件信息后,都会发送获取文件数据的消息,服务器即可进行文件传输

变量qint64 payloadSize用来控制每次文件读取的字节数,progressByte用来存储发送的进度,我这里一次只发送1024个字节,因为区域网传输太快了,文明小传输过程不明显,你们可以调大小,比如1024*64个字节

qt tcp 发送文件,Qt开发,tcp/ip,网络,网络协议,文件传输接着就用while循环控制发送流程,直到发送的字节数等于文件的大小,说明文件数据发送完成

在循环中,要添加几微秒的延时来防止发送的文件帧过快,客户端接收不过来,导致丢包

传输文件的代码如下: 

void FileServer::transferFileData(QTcpSocket *socket)
{

    qint64 payloadSize = 1024*1; //每一帧发送1024*64个字节,控制每次读取文件的大小,从而传输速度

    double progressByte= 0;//发送进度
    qint64 bytesWritten=0;//已经发送的字节数

    while(bytesWritten != m_sendFileSize) {
        double temp = bytesWritten/1.0/m_sendFileSize*100;
        int  progress = static_cast<int>(bytesWritten/1.0/m_sendFileSize*100);
        if(bytesWritten<m_sendFileSize){

            QByteArray DataInfoBlock = m_localFile.read(qMin(m_sendFileSize,payloadSize));

            qint64 WriteBolockSize = socket->write(DataInfoBlock, DataInfoBlock.size());

            //QThread::msleep(1); //添加延时,防止服务端发送文件帧过快,否则发送过快,客户端接收不过来,导致丢包
            QThread::usleep(3); //添加延时,防止服务端发送文件帧过快,否则发送过快,客户端接收不过来,导致丢包
            //等待发送完成,才能继续下次发送,
            if(!socket->waitForBytesWritten(3*1000)) {
                ui->textBrowser->append("网络请求超时");
                return;
            }
            bytesWritten += WriteBolockSize;
            ui->sendProgressBar->setValue(progress);
        }

        if(bytesWritten==m_sendFileSize){
            //LogWrite::LOG_DEBUG(QString("当前更新进度:100%,发送总次数:%1").arg(count), "server_"+socket->localAddress().toString());
            ui->textBrowser->append(QString("当前上传进度:%1/%2 -> %3%").arg(bytesWritten).arg(m_sendFileSize).arg(progress));
            ui->textBrowser->append(QString("-------------对[%1]的文件传输完成!------------------").arg(socket->peerAddress().toString()));
            ui->sendProgressBar->setValue(100);
            m_localFile.close();
            return;
        }
        if(bytesWritten > m_sendFileSize) {
            ui->textBrowser->append("意外情况!!!");
            return;
        }

        if(bytesWritten/1.0/m_sendFileSize > progressByte) {
            ui->textBrowser->append(QString("当前上传进度:%1/%2 -> %3%").arg(bytesWritten).arg(m_sendFileSize).arg(progress));
            progressByte+=0.1;
        }

    }

}

服务端的核心代码讲完了,接下来将客户端的代码,界面如下:

qt tcp 发送文件,Qt开发,tcp/ip,网络,网络协议,文件传输

先定义一个文件类对象,用来存储接收文件的对象,每个下载的文件就是一个文件类对象

qt tcp 发送文件,Qt开发,tcp/ip,网络,网络协议,文件传输

 当连接上服务器后,点击下载文件后,客户端会先发送获取文件的消息

qt tcp 发送文件,Qt开发,tcp/ip,网络,网络协议,文件传输

 服务端收到后,就会获取文件信息(流程上面讲过了),将文件信息发送给客户端

然后客户端根据服务器发送的消息类型处理消息

qt tcp 发送文件,Qt开发,tcp/ip,网络,网络协议,文件传输

 收到服务器发送的文件信息消息后,进行读取,获取文件名,文件大小,用文件类对象进行存储,新建准备写入一个要下载的文件,准备工作完成后,向服务器发送获取文件数据的消息

qt tcp 发送文件,Qt开发,tcp/ip,网络,网络协议,文件传输

 然后设置下载标识为true

bool isDownloading; //是否正在下载标识

标识接下来接下来收到的将全是文件数据,接收即可,直到文件全部接收完成,在将其设为false

文件数据接收的代码流程这样子:

qt tcp 发送文件,Qt开发,tcp/ip,网络,网络协议,文件传输

 实现代码如下:

void FileManager::fileDataRead()
{
    qint64 readBytes = m_tcpSocket->bytesAvailable();
    if(readBytes <0) return;

    int progress = 0;
    // 如果接收的数据大小小于要接收的文件大小,那么继续写入文件
    if(myFile->bytesReceived < myFile->fileSize) {
        // 返回等待读取的传入字节数
        QByteArray data = m_tcpSocket->read(readBytes);
        myFile->bytesReceived+=readBytes;
        ui->textBrowser->append(QString("接收进度:%1/%2(字节)").arg(myFile->bytesReceived).arg(myFile->fileSize));
        progress =static_cast<int>(myFile->bytesReceived*100/myFile->fileSize);
        myFile->progressByte = myFile->bytesReceived;
        myFile->progressStr = QString("%1").arg(progress);
        ui->progressBar->setValue(progress);
        myFile->localFile.write(data);
    }

    // 接收数据完成时
    if (myFile->bytesReceived==myFile->fileSize){
        ui->textBrowser->append(tr("接收文件[%1]成功!").arg(myFile->fileName));
        progress = 100;
        myFile->localFile.close();

        ui->textBrowser->append(QString("接收进度:%1/%2(字节)").arg(myFile->bytesReceived).arg(myFile->fileSize));
        myFile->progressByte = myFile->bytesReceived;
        ui->progressBar->setValue(progress);
        isDownloading = false;
        myFile->initReadData();
    }

    if (myFile->bytesReceived > myFile->fileSize){
        qDebug()<<"myFile->bytesReceived > m_fileSize";
    }
}

最终就达到这个效果啦:

qt tcp 发送文件,Qt开发,tcp/ip,网络,网络协议,文件传输

所有源代码在这里,只有15kB,直接下载就行了 

链接: https://pan.baidu.com/s/1xOuNstwxgEbRbzqQdJA2Aw?pwd=8888 提取码: 8888

有跟多小白私信我说,已运行就提示这个

qt tcp 发送文件,Qt开发,tcp/ip,网络,网络协议,文件传输

这是因为服务器没有开的原因,连接不是导致的,因为我这是一个总工程,里面有两个子项目,一个是客户端,一个是服务器端,教一下怎么切项目吧,如下所示

qt tcp 发送文件,Qt开发,tcp/ip,网络,网络协议,文件传输

除了这样切运行程序,也可以去生成程序的目录下启动

也可以在每个子项目的pro文件里面设置程序生成的位置,依赖库的位置等,这个一般要打包时程序给别的电脑用时必备的,这里就不说了

总结:这个文件传输的例子完成了文件传输的基本流程,基本传输能完成。但是如果要实现文件上传到服务器,并同时下载文件,就需要多线程了,同时,对编码能力也是个提升。界面可以做得好看点,获取到服务器文件列表后,可以选择下载,上传文件,删除文件等操作。难度会瞬间上升。

如下:

qt tcp 发送文件,Qt开发,tcp/ip,网络,网络协议,文件传输文章来源地址https://www.toymoban.com/news/detail-574283.html

到了这里,关于Qt详解实现TCP文件传输例子(文件下载和上传)附源码的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【前端面试】中大文件上传/下载:中等文件代理服务器放行+大文件切片传输+并发请求+localstorage实现断点续传

    目录 切片上传~spark-md5 原理:流式计算+分块处理 文件标识spark-md5:A-B A.切片哈希值合并 B.首尾切片+其他切片前中后各取2M 计算hash:A-B(参考React的Fiber架构) A.线程:web-worker B.空闲:requestIdleCallback 异步并发控制:A-B(参考http2的多路复用) A.promise.allSettled() B.并发数max=

    2024年02月12日
    浏览(56)
  • 【Java 实现文件下载】vue前端+java后端实现文件下载详解(附源码)

    【 写在前面 】前端时间总结了一下有关java文件上传的功能,也给不少读者带来一些帮助,因此今天继续完善文件下载这套体系,希望能给屏幕前的您带来实质性的帮助,其实文件下载最怕的就是中文乱码的现象,当然这个我单独写了一篇文章解释,这里不做详谈。 涉及知识

    2024年02月09日
    浏览(56)
  • 详解JS实现单个或多个文件批量下载的方法

    目录 0.JS简介 前言 单个文件Download 方案一:location.href or window.open 方案二:通过a标签的download属性 方案三:API请求 多个文件批量Download 方案一:按单个文件download方式,循环依次下载 方案二:前端打包成zip download 方案三:后端压缩成zip,然后以文件流url形式,前端调用dow

    2024年02月01日
    浏览(58)
  • 【前端下载文件流详解】前端实现多种类型文件(word,excel,pdf,rar,zip等)的下载,接口返回文件流形式(附源码)

    【 写在前面 】其实之前我也写了有关java实现文件的下载,但是当时是局限于excel文档,针对其他类型的并没有介绍,这次刚好有个客户现场反馈回来的,说我们系统确实能下载报告,但是甲方领导要看所有的报告,这不我每天得一个一个的点击下载,然后再打包给他们领导

    2023年04月24日
    浏览(55)
  • Qt —— 编译Qt5版本QFTP库,并实现连接服务、获取列表、上传、下载、删除文件等操作(附源码、附基于Qt5编译好的QFTP库)

    示例效果1   示例效果2   介绍      QFTP是Qt4的库,Qt5改用了QNetworkAccessManager来代替。但是Qt5提供的QNetworkAccessManager仅支持FTP的上传和下载,所以只能 将QFTP库编译为Qt5的库来进行调用。      QFTP在Github的下载地址:https://github.com/qt/qtftp   客户端源码生成的rele

    2024年01月20日
    浏览(43)
  • Qt下载http文件

    这是一个有问题的版本:  当要下载的文件过大时,程序会崩溃!!!(std::bad_alloc)(所以只可以下载一些小的文件) 我认为这是ba(QByteArray)太大了,要一下子往文件中写入太多的数据,导致new失败了。 修复: Qt 基于http的网络文件下载_qt http下载文件-CSDN博客(参考+引用)

    2024年01月18日
    浏览(34)
  • Qt中使用Http通讯下载文件

    目录 前提 HTTP通讯下载 请求http文件 分解URL网址 创建会话 创建连接 创建请求 发送请求 接收http请求响应 文件操作 获取文件长度 实时下载文件 总结 在某些功能中,会使用到通过Http通讯从网址上下载资源信息。 在这里,我说的资源信息是指以.png、.mp4以及.doc为后缀的文件。

    2023年04月26日
    浏览(44)
  • SecureCRT & SecureFX 9.5 for macOS, Linux, Windows 下载 - 跨平台的多协议终端仿真和文件传输

    SecureCRT SecureFX 9.5 for macOS, Linux, Windows 下载 - 跨平台的多协议终端仿真和文件传输 请访问原文链接:SecureCRT SecureFX 9.5 for macOS, Linux, Windows,查看最新版。原创作品,转载请保留出处。 作者主页:sysin.org SecureCRT 客户端运行于 Windows、Mac 和 Linux,将坚如磐石的终端仿真与强大的

    2024年02月21日
    浏览(39)
  • QT中TCP文件传输

    *免责声明: 1、视频来源于传智播客 2、此方法仅提供参考 本文代码根据B站《零基础入门六天学会QT完整版》中的P52和P53,其中视频有缺失,为了造福其他兄弟,在此补上缺失代码 首先需要创建两个类:ServerWidget和ClientWidget类 以上就是视频中TCP文件传输的代码,若有发现错误

    2023年04月25日
    浏览(36)
  • QT-通过tcp传输文件和文本消息

    在建立连接的基础上增加了发送文件的功能,在接收端和发送端定义了一个枚举类型,用于判别发送的是文件还是文本消息 客户端ui 1.获取端口号和ip地址,进行连接,再次点击即可断开连接 2.点击发送消息按钮,获取文本框内容,将消息发送出去,其中type为文本消息类型

    2024年02月03日
    浏览(36)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包