我的编程空间,编程开发者的网络收藏夹
学习永远不晚

Qt多线程实现网络发送文件功能

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

Qt多线程实现网络发送文件功能

本文实例为大家分享了Qt多线程实现网络发送文件功能的具体代码,供大家参考,具体内容如下

客户端给服务器发送文件,服务器进行接收文件的简单操作

1. 服务器

1. 创建QTcpServer 类的对象

QTcpServer * server = new QTcpServer(this);

2. 进行监听

bool QTcpServer::listen(const QHostAddress &address = QHostAddress::Any, quint16 port = 0)

3. 通过接收 QTcpServer 发出的 newConnection 的信号,进行下一步操作

[signal] void QTcpServer::newConnection()

4. 通过调用  nextPendingConnection 方法获取套接字

// 通过 this->m_server 调用 nextPendConnection
QTcpSocket * socket = server->nextPendingConnection();

5. 接收客户端发来是消息 通过 [signal] void QIODevice::readyRead() 信号

6.客户端下线   [signal] void QAbstractSocket::disconnected() 信号 表示

创建一个子线程类,继承 QThread ,重写父类的run() 方法

在run方法中,创建文件,接收客户端发的文件写进创建的文件中;

接收文件时,要先获取第一次客户端发来的文件大小;

获取客户端第一次发来的文件大小

// 进行接收数据的时候,需要知道客户端发来的文件的大小
// 先将客户端第一次发来的数据的大小读取出来
static int count = 0;   // 判断是否是客户端第一次发来的数据
static int total = 0;   // 记录文件的大小
        if(count == 0)
        {
            this->m_tcp->read((char*)&total, 4);    // 获取文件大小
        }

创建子线程类 并启动子线程

// 创建子线程类对象
MyQThread * myqtread = new MyQThread;
// 启动子线程
myqtread->start();

服务端代码:

widget.h 主线程头文件

#ifndef WIDGET_H
#define WIDGET_H
 
#include <QWidget>
#include <QTcpServer>
 
namespace Ui {
class Widget;
}
 
class Widget : public QWidget
{
    Q_OBJECT
public:
    explicit Widget(QWidget *parent = 0);
    ~Widget();
private slots:
    void on_listenBtn_clicked();
private:
    // 创建QTcpServer 类的对象
    QTcpServer * m_server;
private:
    Ui::Widget *ui;
};
 
#endif // WIDGET_H

widget.cpp  主线程:

#include "widget.h"
#include "ui_widget.h"
 
#include "myqthread.h"
#include <QMessageBox>
 
Widget::Widget(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::Widget)
{
    ui->setupUi(this);
 
    // 设置端口号
    ui->port->setText("8989");
    // 利用多线程进行链接服务器
    // 1. 需要创建一个线程类的子类 ,让其继承Qt中的线程QThread
    // 2. 重写父类的run() 方法,在该函数内部编写子线程要处理的具体业务流程
    // 3. 在主线程中创建子线程对象,new 一个就可以
    // 4. 启动子线程,调用start() 方法
    // 实例化QTcpServer 对象
    this->m_server = new QTcpServer(this);
    // 检验是否接收客户端的连接
    connect(this->m_server, &QTcpServer::newConnection, this, [=]()
    {
        // 获取套接字
        QTcpSocket * tcp = this->m_server->nextPendingConnection();
        // 创建子线程类对象
        MyQThread * myqtread = new MyQThread(tcp);
        // 启动子线程
        myqtread->start();
        // 获取子线程中发来的客户端端口的消息
        connect(myqtread, &MyQThread::ClientDisconnect, this, [=]()
        {
            //弹出对话框提示
            QMessageBox::warning(this, "警告", "客户端已断开连接...");
        });
        // 接收接收完客户端的信号
        connect(myqtread, &MyQThread::OverRecveid, this, [=]()
        {
            //弹出对话框提示
            QMessageBox::information(this, "提示", "已接收文客户端发来的数据");
            // 关闭套接字
            tcp->close();
            // 释放
            tcp->deleteLater();
            // 释放线程
            myqtread->quit();
            myqtread->wait();
            myqtread->deleteLater();
        });
    });
}
 
Widget::~Widget()
{
    delete ui;
}
// 点击监听按钮 进行监听 按钮转到槽的方式
void Widget::on_listenBtn_clicked()
{
    //获取端口号
    unsigned short port = ui->port->text().toUShort();
    //利用this->m_s 调用listen 进行监听
    this->m_server->listen(QHostAddress::Any, port);
}

myqthread.h 子线程头文件

#ifndef MYQTHREAD_H
#define MYQTHREAD_H
 
//#include <QObject>
 
#include <QTcpSocket>
#include <QThread>
 
class MyQThread : public QThread
{
    Q_OBJECT
public:
    explicit MyQThread(QTcpSocket *tcp, QObject *parent = nullptr);
 
    // 2.重写QThread 类中的受保护成员 run() 方法
protected:
    void run();
 
public:
    // 自定义套接字对象 记录主线程传进的套接字对象 tcp
    QTcpSocket * m_tcp;
 
signals:
    // 自定义信号 将服务器接收完客户端发来的数据 告诉主线程
    void OverRecveid();
    // 自定义信号 将客户端断开连接 告诉主线程
    void ClientDisconnect();
 
public slots:
};
 
#endif // MYQTHREAD_H

myqthread.cpp 子线程文件

#include "myqthread.h"
 
#include <QFile>
 
MyQThread::MyQThread(QTcpSocket *tcp, QObject *parent) : QThread(parent)
{
    this->m_tcp = tcp;
}
// 2.重写QThread 类中的受保护成员 run() 方法
void MyQThread::run()
{
    // 1.创建文件 打开文件
    QFile * file = new QFile("recv.txt");
    file->open(QFile::WriteOnly);   // 以只写的方式打开文件
    // 2.检验是否进行读写
    connect(this->m_tcp, &QTcpSocket::readyRead, this, [=]()
    {
        // 进行接收数据的时候,需要知道客户端发来的文件的大小
        // 先将客户端第一次发来的数据的大小读取出来
        static int count = 0;   // 判断是否是客户端第一次发来的数据
        static int total = 0;   // 记录文件的大小
        if(count == 0)
        {
            this->m_tcp->read((char*)&total, 4);    // 获取文件大小
        }
        // 将剩下的数据全部读取出来
        // 获取客户端发来的数据
        QByteArray recvClient = this->m_tcp->readAll(); // 全部接收
        // 将读取的数据的量记录到count中
        count += recvClient.size();
        // 将数据写进文件中
        file->write(recvClient);
        // 判断服务器是否把客户端发来的数据全部读取完
        if(count == total)
        {
            // 关闭套接字
            this->m_tcp->close();
            // 释放套接字
            this->m_tcp->deleteLater();
            // 关闭文件
            file->close();
            file->deleteLater();
            // 自定义一个信号 告诉主线程文件 已接收完毕
            emit OverRecveid();
        }
    });
    // 3.检验客户端是否断开连接
    connect(m_tcp, &QTcpSocket::disconnected, this, [=]()
    {
        // 将客户端断开连接 发送给主线程
        emit this->ClientDisconnect();
    });
    // 调用 exec 进入事件循环 阻塞
    exec();
}

2.客户端

1. 绑定 ip 和 端口号

[virtual] void QAbstractSocket::connectToHost(const QString &hostName, quint16 port, OpenMode openMode = ReadWrite, NetworkLayerProtocol protocol = AnyIPProtocol)

2. 连接服务器

[signal] void QAbstractSocket::connected()

3. 通过套接字 调用 write方法发送消息给服务器

qint64 QIODevice::write(const char *data, qint64 maxSize)

4. 断开连接

[signal] void QAbstractSocket::disconnected()

利用多线程实现 选择文件 发送文件                          

利用第二种多线程的方法                                

1.创建一个新的类,让这个类从QObject中派生                  
2.在这个新的类中添加一个公有的成员函数,函数体是我们要子线程中执行的业务逻辑    
3.在主线程中创建一个QThread对象,这个就是子线程的对象            
4.在主线程中创建一个工作类的对象                          
5.将工作类对象移动到子线程对象中,需要调用QObject类提供的moveThread
6.启动子线程,调用start() 这个线程启动了,当时移动到线程中的对象并没有工作
7.调用工作类的对象函数,让这个函数开始执行,这个时候是在移动到那个子线程中运行的。       

客户端代码: 

mythread.h 任务类头文件

#ifndef MYTHREAD_H
#define MYTHREAD_H
 
#include <QObject>
#include <QTcpSocket>
 
class MyThread : public QObject
{
    Q_OBJECT
public:
    explicit MyThread(QObject *parent = nullptr);
 
    // 连接服务器
    void connectToServer(unsigned short port, QString ip);
    // 发送文件
    void SendFile(QString path);
 
private:
    // 创建QTcpSocket 类的对象
    QTcpSocket * m_socket;
 
signals:
    // 自定义一个信息 告诉主线程 成功连接到服务器
    void ConnectOK();
 
    // 自定义一个信号 告诉主线程服务器已断开连接
    void gameOver();
 
    // 自定义一个信号 将获取的百分比发送给主线程
    void SendPercent(int);
 
public slots:
};
 
#endif // MYTHREAD_H

mythread.cpp 任务类文件

#include "mythread.h"
 
#include <QFileInfo>
#include <QMessageBox>
 
MyThread::MyThread(QObject *parent) : QObject(parent)
{
 
}
// 连接服务器
void MyThread::connectToServer(unsigned short port, QString ip)
{
    // 实例化socket类的对象
    this->m_socket = new QTcpSocket(this);
    // 尝试与服务器取得连接 绑定IP 和端口号
    this->m_socket->connectToHost(ip, port);
    // 检验是否成功与服务器取等连接
    connect(this->m_socket, &QTcpSocket::connected, this, [=]()
    {
        emit this->ConnectOK(); // 自定义一个信号 告诉主线程 成功连接上服务器
    });
    // 检验服务器是否断开连接
    connect(this->m_socket, &QTcpSocket::disconnected, this, [=]()
    {
        this->m_socket->close();    // 关闭套接字
        emit this->gameOver();      // 发送信号 告诉主线程 服务器已断开连接
    });
}
// 发送文件
void MyThread::SendFile(QString path)
{
    // 1.获取文件大小
    QFileInfo info(path);
    int fileSize = info.size();
    // 2.打开文件
    QFile file(path);
    bool ret = file.open(QFile::ReadOnly);
    if(!ret)
    {
        QMessageBox::warning(NULL, "警告", "打开文件失败");
        return; // 退出函数
    }
    // 判断什么时候读完文件
    while(!file.atEnd())
    {
        // 第一次发送文件的时候 将文件的大小发送给服务器
        // 定义一个标记 当标记为0时, 表示第一次发送文件
        static int num = 0;
        if(num == 0)
        {
            this->m_socket->write((char*)&fileSize, 4); // 将文件大小发送给服务器
        }
        // 在循环体中 每次读取一行
        QByteArray line = file.readLine();
        // 每次发送一次数据,就将发送的数据的量记录下来 用于更新进度条
        num += line.size();
        // 基于num值 计算百分比
        int percent = (num*100/fileSize);
        // 将百分比发送给主线程
        emit this->SendPercent(percent);
        // 将读取的数据通过套接字对象发送给服务器
        this->m_socket->write(line);
    }
}

widget.h 主线程头文件

#ifndef WIDGET_H
#define WIDGET_H
 
#include <QWidget>
 
namespace Ui {
class Widget;
}
 
class Widget : public QWidget
{
    Q_OBJECT
 
public:
    explicit Widget(QWidget *parent = 0);
    ~Widget();
 
signals:
    // 自定义一个信号 告诉子线程进行链接服务器
    void TellToConnect(unsigned short port, QString ip);
    // 自定义一个信号 将选中的文件路径发送给任务类
    void SendToFile(QString);
 
private slots:
    void on_connectBtn_clicked();
 
    void on_selectBtn_clicked();
 
    void on_sendBtn_clicked();
 
private:
    QString m_path;
private:
    Ui::Widget *ui;
};
 
#endif // WIDGET_H

widget.cpp

#include "widget.h"
#include "ui_widget.h"
 
#include <QFileDialog>
#include <QMessageBox>
#include <QThread>
#include "mythread.h"
 
Widget::Widget(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::Widget)
{
    ui->setupUi(this);
 
    // 利用多线程实现 选择文件 发送文件
    // 利用第二种多线程的方法
    // 1.创建一个新的类,让这个类从QObject中派生
    // 2.在这个新的类中添加一个公有的成员函数,函数体是我们要子线程中执行的业务逻辑
    // 3.在主线程中创建一个QThread对象,这个就是子线程的对象
    // 4.在主线程中创建一个工作类的对象
    // 5.将工作类对象移动到子线程对象中,需要调用QObject类提供的moveThread方法
    // 6.启动子线程,调用start() 这个线程启动了,当时移动到线程中的对象并没有工作
    // 7.调用工作类的对象函数,让这个函数开始执行,这个时候是在移动到那个子线程中运行的。
 
    // 1.创建QThread对象
    QThread *t = new QThread;
    // 2.创建任务类的对象
    MyThread * working = new MyThread;
    // 3.将任务类对象移动到子线程中
    working->moveToThread(t);
    // 启动子线程
    t->start();
    // 4.设置IP 端口号
    ui->ip_lineEide->setText("127.0.0.1");
    ui->port_lineEdit->setText("8989");
    // 5.设置进度条
    ui->progressBar->setRange(0, 100);  // 进度条的范围
    ui->progressBar->setValue(0);       // 初始化为0
    // 6.更新进度条 通过连接任务类发来的信号 实现
    connect(working, &MyThread::SendPercent, ui->progressBar, &QProgressBar::setValue);
    // 7.接收任务类发来的成功连接到服务器 信号
    connect(working, &MyThread::ConnectOK, this, [=]()
    {
        QMessageBox::information(this, "提示", "成功连接到服务器");
        // 将文件按钮设置成不可用状态
        ui->sendBtn->setDisabled(false);
    });
    // 8.连接任务类发来的断开连接的信号
    connect(working, &MyThread::gameOver, this, [=]()
    {
        QMessageBox::warning(this, "警告", "服务器已断开连接");
        //释放支援
        t->quit();
        t->wait();
        t->deleteLater();
        working->deleteLater();
        // 将文件按钮设置成可用状态
        ui->sendBtn->setDisabled(true);
    });
    // 7.将信号和工作类对象中的任务函数连接
    connect(this, &Widget::TellToConnect, working, &MyThread::connectToServer);
    // 8.将文件路径发给任务函数
    connect(this, &Widget::SendToFile, working, &MyThread::SendFile);
    // 9.将发送文件按钮设置成可用状态
    ui->sendBtn->setDisabled(true);
}
 
Widget::~Widget()
{
    delete ui;
}
// 连接服务器
void Widget::on_connectBtn_clicked()
{
    // 获取ip 和 端口号
    QString ip = ui->ip_lineEide->text();
    unsigned short port = ui->port_lineEdit->text().toShort();
    // 将ip 和 端口号 发送取出
    emit this->TellToConnect(port, ip);
    // 将发送文件按钮设置成不可用状态
    ui->sendBtn->setDisabled(false);
}
// 选中文件
void Widget::on_selectBtn_clicked()
{
    m_path = QFileDialog::getOpenFileName();  // 打开文件选择对话框
    // 判断选中的对话框不能为空
    if(m_path.isEmpty())
        QMessageBox::warning(this, "警告", "选中要发送的文件不能为空");
    // 将选中的文件路径显示到单行编辑框中
    ui->filePath_lineEdit->setText(m_path);
}
// 发送文件
void Widget::on_sendBtn_clicked()
{
    // 将选中的文件路径发送给任务类
    emit this->SendToFile(m_path);
}

程序运行结果:

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持编程网。

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

Qt多线程实现网络发送文件功能

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

Android实现网络多线程文件下载

实现原理(1)首先获得下载文件的长度,然后设置本地文件的长度。(2)根据文件长度和线程数计算每条线程下载的数据长度和下载位置。如:文件的长度为6M,线程数为3,那么,每条线程下载的数据长度为2M,每条线程开始下载的位置如下图所示:(网上找的
2022-06-06

PHPMailer发送邮件功能实现流程

随着企业化的管理越来越规范,各种项目管理系统中,都需要加入到邮件实时通知功能,所以在项目中如何整合发邮件功能,其实也是很重要的一点。本文为大家介绍了PHP实现邮件实时通知功能的示例代码,需要的可以参考一下
2022-12-21

Android实现网络多线程断点续传下载功能

我们编写的是Andorid的HTTP协议多线程断点下载应用程序。直接使用单线程下载HTTP文件对我们来说是一件非常简单的事。那么,多线程断点需要什么功能?1.多线程下载 2.支持断点使用多线程的好处:使用多线程下载会提升文件下载的速度 原理
2022-06-06

qt多线程文件传输项目怎么实现

要实现一个基于Qt多线程的文件传输项目,可以按照以下步骤进行:创建一个Qt项目:首先打开Qt Creator,创建一个新的Qt项目,并选择“Qt Widgets Application”模板。设计界面:设计一个简单的界面,包括选择文件和目标
qt多线程文件传输项目怎么实现
2024-03-06

python使用requests实现发送带文件请求功能

这篇文章主要介绍了python使用requests实现发送带文件请求,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
2022-12-08

vue如何实现pdf文件发送到邮箱功能

这篇文章主要介绍了vue如何实现pdf文件发送到邮箱功能的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇vue如何实现pdf文件发送到邮箱功能文章都会有所收获,下面我们一起来看看吧。需求: vue实现pdf文件发
2023-06-30

Java网络编程TCP怎么实现文件上传功能

这篇文章给大家分享的是有关Java网络编程TCP怎么实现文件上传功能的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。具体内容如下客户端:package com.kuang.lesson02;import java.
2023-06-20

Shell脚本实现备份系统文件并邮件发送功能

本篇内容介绍了“Shell脚本实现备份系统文件并邮件发送功能”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!1.安装MUTT邮件客户端# yu
2023-06-09

Qt音视频开发之视频文件保存功能的实现

和音频存储类似,视频的存储也对应三种格式,视频最原始的数据是yuv(音频对应pcm),视频压缩后的数据是h264(音频对应aac)。本文将利用Qt实现视频文件保存功能,感兴趣的可以了解一下
2022-12-08

计算机网络编程 | 并发服务器代码实现(多进程/多线程)

欢迎关注博主 Mindtechnist 或加入【Linux C/C++/Python社区】一起学习和分享Linux、C、C++、Python、Matlab,机器人运动控制、多机器人协作,智能优化算法,滤波估计、多传感器信息融合,机器学
2023-08-18

在Java项目中如何利用多线程实现文件下载功能

这篇文章将为大家详细讲解有关在Java项目中如何利用多线程实现文件下载功能,文章内容质量较高,因此小编分享给大家做个参考,希望大家阅读完这篇文章后对相关知识有一定的了解。具体内容如下import java.io.File; import j
2023-05-31

WordPress实现回复文章评论后发送邮件通知的功能

本文实例讲述了WordPress实现回复文章评论后发送邮件通知的功能。分享给大家供大家参考,具体如下: 很多时候,人们都希望在自己的评论被管理员回复后会收到通知。该函数的作用就是回复后自动邮件通知评论者。 把下面的代码加到wordpress
2022-06-12

怎么在Android应用中实现一个网络多线程断点续传下载功能

怎么在Android应用中实现一个网络多线程断点续传下载功能?很多新手对此不是很清楚,为了帮助大家解决这个难题,下面小编将为大家详细讲解,有这方面需求的人可以来学习下,希望你能有所收获。原理多线程下载的原理就是将要下载的文件分成若干份,其中
2023-05-31

在Java项目中如果发送http请求实现文件上传功能

在Java项目中如果发送http请求实现文件上传功能?相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。具体代码如下所示:package wxapi.WxHelper; import
2023-05-31

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录