Qt实现基于多线程的文件传输(服务端,客户端)

2023-11-09

1. 效果

先看看效果图

  • 这是传输文件完成的界面
    在这里插入图片描述
  • 客户端
    在这里插入图片描述
  • 服务端
    在这里插入图片描述

2. 知识准备

其实文件传输和聊天室十分相似,只不过一个传输的是文字,一个传输的是文件,而这方面的知识,我已经在前面的博客写过了,不了解的同学可以去看一下

还有多线程相关的知识

2.1 关于多线程

这次是用多线程实现的文件传输系统,其中对客户端来说,子线程负责连接服务器,发送文件,主线程负责修改进度条,对服务端来说,也是用子线程来处理客户端的请求

2.2 关于文件传输

文件传输采用的是,对客户端,首先是发送出整个文件的大小,需要用到QFileInfo这个类,然后再发送文件

对服务端,先接收文件的大小,然后判断,当接收的文件大小等于第一次接收的文件大小时,停止接收,断开连接

3. 源代码

我在代码里面都有非常详细的注释,所以就直接放上代码啦

3.1 客户端

头文件 mainwindow.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>

QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    MainWindow(QWidget *parent = nullptr);
    ~MainWindow();

signals:
    void startConnect(unsigned short,QString);
    // 发送文件信号
    void sendFile(QString path);

private slots:
    void on_connectServer_clicked();

    void on_selFile_clicked();

    void on_sendFile_clicked();

 private:
    Ui::MainWindow *ui;
};
#endif // MAINWINDOW_H

源文件 mainwindow.cpp

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QMessageBox>
#include <QThread>
#include "sendfile.h"
#include <QFileDialog>
MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    // 设置IP和端口
    ui->ip->setText("127.0.0.1");
    ui->port->setText("8989");

    // 设置进度条
    ui->progressBar->setRange(0,100);
    ui->progressBar->setValue(0);

    // 客户端在子线程中连接服务器
    // 创建线程对象
    QThread* t = new QThread;

    // 创建任务对象
    SendFile* worker = new SendFile;

    // 将worker移动到子线程t中
    worker->moveToThread(t);


    // 当发送sendFile信号,让worker的sendFile函数处理(子线程)
    connect(this,&MainWindow::sendFile,worker,&SendFile::sendFile);


    // 通过信号,让worker开始工作
    // 因为worker 已经移动到了子线程中,因此connectServer这个槽函数是在子线程中执行的
    connect(this,&MainWindow::startConnect,worker,&SendFile::connectServer);

    // 处理子线程发送的信号
    // 连接成功
    connect(worker,&SendFile::connectOK,this,[=](){
        QMessageBox::information(this,"连接服务器","已经成功的连接了服务器,恭喜!");
    });

    // 断开连接
    connect(worker,&SendFile::gameover,this,[=](){
        // 资源释放
        t->quit();
        t->wait();
        worker->deleteLater();
        t->deleteLater();
    });

    connect(worker,&SendFile::curPercent,ui->progressBar,&QProgressBar::setValue);
    // 启动线程
    t->start();
}

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


void MainWindow::on_connectServer_clicked()
{
    QString ip = ui->ip->text();
    unsigned short port = ui->port->text().toUShort();
    emit startConnect(port,ip);

}

void MainWindow::on_selFile_clicked()
{
    QString path = QFileDialog::getSaveFileName();
    // 判断路径是否为空
    if(path.isEmpty())
    {
        QMessageBox::warning(this,"打开文件","选择的文件路径不能为空");
        return;
    }
    ui->filePath->setText(path);
}



void MainWindow::on_sendFile_clicked()
{
    // 发送文件信号
    emit sendFile(ui->filePath->text());
}

头文件 Send File.h

#ifndef SENDFILE_H
#define SENDFILE_H

#include <QObject>
#include <QTcpSocket>

class SendFile : public QObject
{
    Q_OBJECT
public:
    explicit SendFile(QObject *parent = nullptr);

    // 连接服务器
    void connectServer(unsigned short port,QString ip);

    // 发送文件
    void sendFile(QString path);

signals:
    // 通知主线程连接成功
    void connectOK();
    // 通知主线程连接成功
    void gameover();
    // 通知主线程发送文件进度百分比
    void curPercent(int num);


private:
    QTcpSocket* m_tcp;
};

#endif // SENDFILE_H

源文件SendFile.cpp

#include "sendfile.h"

#include <QFile>
#include <QHostAddress>
#include <QFileInfo>

SendFile::SendFile(QObject* parent) : QObject(parent)
{

}

void SendFile::connectServer(unsigned short port, QString ip)
{
    m_tcp = new QTcpSocket;
    m_tcp->connectToHost(QHostAddress(ip),port);

    // 通知主线程连接成功
    connect(m_tcp,&QTcpSocket::connected,this,&SendFile::connectOK);

    // 通知主线程断开连接
    connect(m_tcp,&QTcpSocket::disconnected,this,[=](){
        // 断开连接,释放资源
        m_tcp->close();
        m_tcp->deleteLater();
        emit gameover();
    });
}

void SendFile::sendFile(QString path)
{
    QFile file(path);
    // 获取文件信息
    QFileInfo info(path);
    int fileSize = info.size();

    file.open(QFile::ReadOnly);

    // 一行一行的读文件
    while(!file.atEnd()){
        static int num = 0;
        // 为了让服务器端知道什么时候停止接收,所以得发送文件的大小
        if(num ==0){
            m_tcp->write((char*)&fileSize,4);
        }

        QByteArray line = file.readLine();
        // 计算百分比,发给主线程
        num +=line.size();
        int percent =(num*100/fileSize);
        emit curPercent(percent);
        m_tcp->write(line);


    }

}

3.2 服务端

头文件mainwindow.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include <QTcpServer>

QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    MainWindow(QWidget *parent = nullptr);
    ~MainWindow();

private slots:
    void on_setListen_clicked();

private:
    Ui::MainWindow *ui;
    QTcpServer* m_s;

};
#endif // MAINWINDOW_H

源文件maindow.cpp

#include "mainwindow.h"
#include "ui_mainwindow.h"

#include <QMessageBox>
#include <QTcpSocket>
#include "recvfile.h"

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

    m_s = new QTcpServer(this);


    connect(m_s,&QTcpServer::newConnection,this,[=](){
        QTcpSocket* tcp = m_s->nextPendingConnection();
        // 创建子线程,tcp通过参数传递
        RecvFile* subThread = new RecvFile(tcp);
        subThread->start();
        connect(subThread,&RecvFile::over,this,[=](){
           subThread->exit();
           subThread->wait();
           subThread->deleteLater();
           QMessageBox::information(this,"文件接受","文件接收完毕!!!");
        });
    });
 
}

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


void MainWindow::on_setListen_clicked()
{
    unsigned short port = ui->port->text().toUShort();
    m_s->listen(QHostAddress::Any,port);

}

头文件recvfile.h

#ifndef RECVFILE_H
#define RECVFILE_H

#include <QThread>
#include <QTcpSocket>
class RecvFile : public QThread
{
    Q_OBJECT
public:
    explicit RecvFile(QTcpSocket* tcp,QObject *parent = nullptr);

protected:
    void run() override;

private:
    QTcpSocket* m_tcp;

signals:
    void over();
};

#endif // RECVFILE_H

源文件recvfile.cpp

#include "recvfile.h"
#include <QFile>
RecvFile::RecvFile(QTcpSocket* tcp,QObject *parent) : QThread(parent)
{
    m_tcp = tcp;
}

void RecvFile::run()
{
    QFile* file = new QFile("recv.txt");
    file->open(QFile::WriteOnly);

    // 接收数据
    connect(m_tcp,&QTcpSocket::readyRead,this,[=](){
        static int count = 0;
        static int total = 0;
        if(count == 0){
            m_tcp->read((char*)&total,4);
        }
        // 读出剩余数据
        QByteArray all = m_tcp->readAll();
        count += all.size();
        file->write(all);

        if(count == total){
            m_tcp->close();
            m_tcp->deleteLater();
            file->close();
            file->deleteLater();
            emit over();
        }
    });

    // 进入事件循环
    exec();
}

3.4 文件目录

在这里插入图片描述

4. 结束语

如果有些小伙伴需要工程文件等,可以联系我

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Qt实现基于多线程的文件传输(服务端,客户端) 的相关文章

  • C# 打印问题(RichTextBox)

    我想打印我的 RichTextBox eintragRichTextBox 的内容 我现在有这个代码 private void druckenPictureBox Click object sender EventArgs e PrintD
  • 您可以从基本 Win32 控制台模板应用程序中的 C#/Winrt 组件调用(不是 WinForm/abstractions/wrappers 或使用 C++/Winrt 模板)吗?)

    我有一个现有的程序 win32 x86 控制台应用程序 需要调用托管代码 来自 Net 的 C dll The dll不暴露给 COM 但可以从 C WinRT 组件调用并由 C WinRT 控制台模板应用引用 BUT即使安装了 C Win
  • 在路由mvc 4中添加公司名称

    我一直在尝试为 Facebook 等用户提供在 URL 中添加公司名称的选项 http localhost 50753 MyCompany Login 我尝试过不同的网址 但没有成功 routes MapRoute name Default
  • 如何在另一个应用程序中挂钩 api 调用

    我正在尝试挂钩另一个应用程序的 ExtTextOut 和 DrawTextExt GDI 方法调用 我知道我需要使用 GetProcAddress 来查找 gdi32 dll 中那些方法的地址 并用我的函数的地址覆盖我想要挂钩的进程中的地址
  • 在 Java 中创建 T 的新实例

    在C 中 我们可以定义一个泛型class A
  • 在 OnModelCreating 期间设置列名称

    Issue 我目前正在尝试通过设置的属性为我的表及其列添加前缀 我正在使用实体框架核心 我已经正确地为表名添加了前缀 但我似乎无法弄清楚列的前缀 我有一种感觉 我需要使用反射 我已经留下了我的 可能很糟糕的 反思尝试 有人有办法在实体中设置
  • 有没有办法在 xcode 上使用 c++0x ?我想使用 gcc 4.4 或更高版本

    我想使用 gcc 4 4 或更高版本进行 iphone 开发 有人知道怎么做吗 不 你不知道 相信我 你不会 Apple 仍保留 gcc 4 2 1 因为 4 2 2 及更高版本使用 GPLv3 这意味着他们必须放弃对其平台的控制 对于 i
  • 将完整模板参数值映射到原始类型

    我想将数字映射到类型 在这个例子中 我将创建一个函数 将 sizeof 结果映射到有符号的原始类型 我想知道是否有更好的方法来完成我在现代 C 中所做的事情 即采用模板化值并将其转换为类型 现在 这可以将大小转换为已知类型 但我似乎无法在标
  • 从代码中,如何创建对存储在附加属性中的对象的属性的绑定?

    我们有一个继承的附加属性来存储一个对象 在可视化树的更下方 我们希望从代码绑定到该对象的属性 通常我们像这样构建绑定的路径部分 var someBinding new Binding Path new PropertyPath Attach
  • 运行需要 MySql.Data 的内置 .NET 应用程序

    我在运行我编写的内置 NET 应用程序时遇到问题 我的应用程序使用最新的 MySql 连接器 该连接器安装在我的系统上 当我尝试将其添加为引用时 该连接器显示为 NET 4 Framwork 组件 当我在环境中以调试模式运行应用程序时 一切
  • C# 5 async/await 线程机制感觉不对?

    为什么让调用线程进入异步方法直到内部 等待 一旦调用异步方法就生成一个线程 这不是更干净吗 这样您就可以确定异步方法会立即返回 您不必担心在异步方法的早期阶段没有做任何昂贵的事情 我倾向于知道某个方法是否要在 我的 线程上执行代码 不管是堵
  • 获取 boost Spirit 语法中的当前行

    我正在尝试使用 boostspirit 获取正在解析的文件的当前行 我创建了一个语法类和结构来解析我的命令 我还想跟踪在哪一行找到命令并将其解析到我的结构中 我将 istream 文件迭代器包装在 multi pass 迭代器中 然后将其包
  • 如何对 NServiceBus.Configure.WithWeb() 进行单元测试?

    我正在构建一个 WCF 服务 该服务接收外部 IP 上的请求并将其转换为通过 NServiceBus 发送的消息 我的单元测试之一调用Global Application Start 它执行应用程序的配置 然后尝试将 Web 服务解析为 验
  • 为什么 Cdecl 调用在“标准”P/Invoke 约定中经常不匹配?

    我正在开发一个相当大的代码库 其中 C 功能是从 C P Invoked 的 我们的代码库中有很多调用 例如 C extern C int stdcall InvokedFunction int 使用相应的 C DllImport CPlu
  • Project Euler #8,我不明白我哪里出了问题[关闭]

    Closed 这个问题是无法重现或由拼写错误引起 help closed questions 目前不接受答案 我正在做项目欧拉第八题 https projecteuler net problem 8 其中我得到了这个大得离谱的数字 7316
  • 从浏览器访问本地文件?

    您好 我想从浏览器访问系统的本地文件 由于涉及大量安全检查 是否可以通过某种方式实现这一目标 或使用 ActiveX 或 Java Applet 的任何其他工作环境 请帮帮我 要通过浏览器访问本地文件 您可以使用签名的 Java Apple
  • 在 OpenGL 中渲染纹理 1 到 1

    所以我想做的是使用 OpenGL 和 C 将纹理渲染到平面上 作为显示图像的一种方式 但是我需要确保在渲染纹理时没有对纹理进行任何处理 抗锯齿 插值 平滑 模糊等 这是 OpenGL 处理渲染纹理的默认方式吗 或者是否需要设置一些标志才能禁
  • 如何调试 .NET 运行时中的内部错误?

    我正在尝试调试一些处理大文件的工作 代码本身works 但 NET 运行时本身会报告零星错误 对于上下文 这里的处理是一个 1 5GB 文件 仅加载到内存中一次 在循环中处理和释放 故意尝试重现此否则不可预测的错误 我的测试片段基本上是 t
  • 如何在 winforms 应用程序的主屏幕显示之前显示欢迎屏幕?

    我想在应用程序启动时加载欢迎屏幕 然后用户单击欢迎屏幕上的按钮 然后关闭欢迎屏幕 最后显示主屏幕 static void Main startup method being called Application EnableVisualSt
  • 使用 using 声明时,非限定名称查找如何工作?

    根据 C 标准 这是格式错误还是格式良好 namespace M struct i namespace N static int i 1 using M i using N i int main sizeof i Clang 拒绝它 GCC

随机推荐

  • sklearn中fit_transform,transform和fit函数的区别和作用详解

    写在前面 fit和transform没有任何关系 仅仅是数据处理的两个不同环节 之所以出来fit transform这个函数名 仅仅是为了写代码方便 会高效一点 sklearn里的封装好的各种算法使用前都要fit fit相对于整个代码而言
  • 简单使用iPhone自带视频播放器

    利用苹果自带的视频播放器播放视频 在调用方法前 我们需要包含头文件 import
  • 生成测试数据神器:使用python的faker库

    一 faker是啥 Faker是一个Python包 开源的GITHUB项目 主要用来生成大量的伪数据 使用Faker包 无需再手动生成或者手写随机数来生成数据 只需要调用Faker提供的方法 即可完成数据的生成 二 Faker的使用 引用包
  • electron --unsafely-treat-insecure-origin-as-secure 问题解决 navigator.mediaDevices = undefined

    问题原因 由于electron mainWindow loadURL http 127 0 0 1 访问是已http协议 而chrome浏览器在访问http请求时考虑隐私安全是无法打开许多Web API的 如 navigator media
  • 求字符串可匹配的最大长度

    如 text abcdlijkfgd query abcdefg 最大匹配为 abcd 为4 编写一个函数 求字符串可匹配的最大长度 如果是完全匹配 则用很多种方法 如BF KMP sunday等字符串匹配算法 KMP是比较常见的 其思想也
  • 软件项目管理的成功法则

    1 平衡原则 在我们讨论软件项目为什么会失败时可以列出了很多的原因 答案有很多 如管理问题 技术问题 人员问题等等 但是有一个根本的思想问题是最容易忽视的 也是软件系统的用户 软件开发商 销售代理商最不想正视的 那就是 需求 资源 工期 质
  • Jmeter之响应断言

    断言有很多种 最最最常用的一种就是响应断言 目前我也只接触过这么一种 详情 Main sample and sub samples 断言应用于主采样器和子采样器 Main sample only 断言仅应用于主采样器 Sub samples
  • 排序算法的稳定与不稳定

    稳定的排序算法 通俗地讲就是能保证排序前2个相等的数其在序列的前后位置顺序和排序后它们两个的前后位置顺序相同 在简单形式化一下 如果Ai Aj Ai原来在位置前 排序后Ai还是要在Aj位置前 没错 其实就是有两个排序关键字的时候 稳定排序可
  • 2023华为OD机试真题-数字加减游戏(JAVA、Python、C++)

    题目描述 小明在玩一个数字加减游戏 只使用加法或者减法 将一个数字s变成数字t 每个回合 小明可以用当前的数字加上或减去一个数字 现在有两种数字可以用来加减 分别为 其中b没有使用次数限制 请问小明最少可以用多少次a 才能将数字s变成数字t
  • 我所不知道的TCP Socket编程(五)-交换数据、套接字读写操作

    五 交换数据 已经建立了服务器和客户端的链接 现在需要让它们进行数据交换 你可以将TCP连接想象成一串连接了本地套接字和远程套接字的管子 我们可以沿着这个管子发送和接受数据 实际中 数据被编码为TCP IP分组 经过多台路由器和主机 抵达终
  • 使用YOLOv5模型进行目标检测!

    点击上方 小白学视觉 选择加 星标 或 置顶 重磅干货 第一时间送达 目标检测是计算机视觉领域的一大任务 大致分为一阶段目标检测与两阶段目标检测 其中一阶段目标检测模型以YOLO系列为代表 最新的YOLOv5在各个数据集上体现出收敛速度快
  • 实现Excel的导入、导出

    实现Excel的导入 导出 关于excel的操作在工作中经常会遇到 如果只是一次性使用的话 最简单的方式就是通过数据库的可视化工具 如Navicat 查询结果集之后直接一键生成excel了 当然这只能解燃眉之急 并不是长久之计 首先Exce
  • PAT C入门题目-7-12 日期格式化 (5 分)

    7 12 日期格式化 5 分 世界上不同国家有不同的写日期的习惯 比如美国人习惯写成 月 日 年 而中国人习惯写成 年 月 日 下面请你写个程序 自动把读入的美国格式的日期改写成中国习惯的日期 输入格式 输入在一行中按照 mm dd yyy
  • 小车+摄像头 +ros+gazebo+yolo仿真

    一 项目代码下载 https blog csdn net WhiffeYF article details 109187804 下载到 catkin ws2 src 中 这几个文件 其中 darknet ros 用于yolo的目标检测 mr
  • 【关于PyCharm安装和加载Pyecharts可视化库的方法和安装过程中出现的No Module Named XXX的解决方案】

    作者 亮马桥胡歌Wechat changxu1129 Echarts 是百度开源的一个数据可视化 JS 库 主要用于数据可视化 点击访问Echarts官网 http echarts baidu com index html 点此直接访问Py
  • Telink 825x 蓝牙开发笔记1

    Telink 825x 蓝牙开发笔记1 背景 美国贸易战导致芯片等模组价格上涨 为了以后长期发展需要研究国产蓝牙 Telink 一 环境搭建 1 软件下载 IDE Telink IDE 1 3 量产工具 Telink BDT exe v5
  • robots.txt 如何禁止蜘蛛(百度,360,搜狗,谷歌)搜索引擎获取页面内容

    什么是蜘蛛抓取 搜索引擎使用spider程序自动访问互联网上的网页并获取网页信息 spider在访问一个网站时 会首先会检查该网站的根域下是否有一个叫做robots txt的纯文本文件 您可以在您的网站中创建一个纯文本文件robots tx
  • 二十一. Kubernetes 配置的创建与使用

    目录 一 配置基础 二 Secret 配置介绍与使用示例 Secret 的创建 Secret 的使用 1 pod env 中作为环境变量获取使用 Secret 2 以卷挂载的方式使用 Secret 三 ConfigMap 介绍与使用示例 C
  • 卷积神经网络「失陷」,CoordConv来填坑

    卷积神经网络 失陷 CoordConv来填坑 作者 Rosanne Liu等 卷积神经网络拥有权重共享 局部连接和平移等变性等非常优秀的属性 使其在多种视觉任务上取得了极大成功 但在涉及坐标建模的任务上 如目标检测 图像生成等 其优势反而成
  • Qt实现基于多线程的文件传输(服务端,客户端)

    1 效果 先看看效果图 这是传输文件完成的界面 客户端 服务端 2 知识准备 其实文件传输和聊天室十分相似 只不过一个传输的是文字 一个传输的是文件 而这方面的知识 我已经在前面的博客写过了 不了解的同学可以去看一下 C 网络编程 Qt实现