QT中通过TCP协议多线程的文件传输(客户端)

2024-08-23 07:12

本文主要是介绍QT中通过TCP协议多线程的文件传输(客户端),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

首先,新建一个项目,我命名为了SendFileClient

 首先我们要在pro文件中 代码第一行加入network的后缀

 

一、窗口搭建

 如图所示,在第一个QWidget中让客户端输入IP端口号   连接服务器

第二个Qwidget 设置一个LineEdit,供客户端选择要发送的文件

在下面设置一个 progressBar ,用来显示文件上传的进度

在最下面设置一个按钮点击发送文件。

二、创建一个新类

既然运用到了多线程,我们将连接服务器,选择文件,发送文件的任务交给子线程,主线程去管理进度条的任务

右键项目add new新建一个类 

继承Qobject,这里我取名为sendfile

在sendfile.h中定义两个函数用来连接服务器,发送文件

mainwindow的操作

连接服务器

首先在mainwindow的构造函数中 初始化 ip ,端口号进度条 的值

我要将发送文件连接服务器在子线程中操作的话,我们就要先创建一个线程对象和任务对象,将任务对象通过moveToThread函数移动到创建出来的线程中去工作。

 接下来我们实现 连接服务器的操作

右键ui中的连接服务器转到槽函数的clicked()

 函数中的内容

 要提前在mainwindow.h在定义一个信号,提醒worker对象中的connectSever开始执行

 

 在上面的构造函数中,用connect如果收到startConnect的信号,就去执行woker中的connectSever函数

然后启动子线程用start()

看到这先去看sendfile操作再回来看下面的  1

 这时主线程收到了子线程发来的connectOK,就知道成功连接到了服务器
如果收到了gameover,就知道服务器断开了,进行资源释放

发送文件

给选择文件添加一个处理函数 

发送文件同样

 提前在mainwindow.h中添加好这个信号

 在mainwindow的构造函数中添加一个connect表示如果我收到了发来的sendfile信号,就去完成sendfile类中的send函数

这里跳转到sendfile后面观看  2

 更新进度条

在构造函数中添加connect,如果收到curpencent信号,将信号中传来的pencent去设置进度条的值

mainwindow到这也结束了

sendfile的操作

1

现在sendfile.h文件中定义一个QTcpSocket的套接字,用于通信

 

 完善一下connectSever操作

 提前在sendfile.h中先定义好信号;

第一次看到这可以回去看了

2

将文件发送给服务器,将文件传输进度通过信号告诉主线程

提前添加一个curpencent的信号

这时回到主窗口更新进度条,senfile到这一步就完成了

完整代码

mainwindow.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H#include <QMainWindow>
#include"sendfile.h"
#include<QThread>namespace Ui {
class MainWindow;
}class MainWindow : public QMainWindow
{Q_OBJECTsignals:void startconnect(unsigned short ,QString);void sendfile(QString path);public:explicit MainWindow(QWidget *parent = nullptr);~MainWindow();private slots:void on_pushButton_clicked();void on_selFile_clicked();void on_sendFile_clicked();private:Ui::MainWindow *ui;QThread *t;sendFile * work;
};#endif // MAINWINDOW_H

mainwindow.cpp

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include<QMessageBox>
#include<QFileDialog>
MainWindow::MainWindow(QWidget *parent) :QMainWindow(parent),ui(new Ui::MainWindow)
{ui->setupUi(this);ui->ip->setText("127.0.0.1");ui->port->setText("8899");ui->progressBar->setRange(0,100);ui->progressBar->setValue(0);t = new QThread;work = new sendFile; //实例化一个sendfile类work->moveToThread(t);//将实例化的类要执行的程序移动到线程里去执行connect(this,&MainWindow::sendfile,work,&sendFile::send);connect(this,&MainWindow::startconnect,work,&sendFile::connectSever);//如果点击连接按钮,这里会接收到一个startconnct的槽函数,然后去执行work中的connctSever操作connect(work,&sendFile::connectOK,this,[=](){ //如果connctsever连接成功,会发来一个connctok的槽函数QMessageBox::information(this,"连接服务器","连接服务器成功");});connect(work,&sendFile::gameover,this,[=](){  //如果断开连接会发来一个gameover的槽函数t->quit();t->wait();t->deleteLater();work->deleteLater();});connect(work,&sendFile::curpencent,ui->progressBar,&QProgressBar::setValue);t->start();
}MainWindow::~MainWindow()
{delete ui;
}void MainWindow::on_pushButton_clicked()
{unsigned short port = ui->port->text().toUShort();//将ui中的端口号转换为short类型取出保存QString ip = ui->ip->text().toUtf8();//将对象转换为UTF-8编码的字节序列,存储在QString对象中,emit startconnect(port,ip);//发送一个开始连接的信号
}void MainWindow::on_selFile_clicked()
{QString path = QFileDialog::getOpenFileName();//通过此方法可以得到某个磁盘文件的绝对路径if(path.isEmpty()){QMessageBox::warning(this,"选择文件","选择的文件不能为空");//如果选择文件为空弹出一个警告对话窗return;}ui->filePath->setText(path);//将选择好的文件设置给文本框
}void MainWindow::on_sendFile_clicked()
{emit sendfile(ui->filePath->text());//因为发送文件的操作是在子线程中做的,所以发送一个信号告诉子线程文件路径名
}

sendfile.h

#ifndef SENDFILE_H
#define SENDFILE_H#include <QObject>
#include<QTcpSocket>
#include <QHostAddress>class sendFile : public QObject
{Q_OBJECT
public:explicit sendFile(QObject *parent = nullptr);void connectSever(unsigned short port, QString ip);//连接服务器void send(QString path);//发送文件signals:void connectOK();void gameover();void curpencent(int );private:QTcpSocket *tcp;};#endif // SENDFILE_H

sendfile.cpp

#include "sendfile.h"
#include <QFile>
#include <QFileInfo>
#include <QHostAddress>sendFile::sendFile(QObject *parent) : QObject(parent)
{}void sendFile::connectSever(unsigned short port, QString ip)
{tcp = new QTcpSocket;//实例化套接字tcp->connectToHost(QHostAddress(ip),port);//通过给定的ip,port连接服务器connect(tcp,&QTcpSocket::connected,this,&sendFile::connectOK);//如果连接成功就发送一个connectOK的信号告诉主线程connect(tcp,&QTcpSocket::disconnected,[=](){//如果断开连接就关闭套接字并释放,发送gameover的信号给主线程tcp->close();tcp->deleteLater();emit  gameover();});
}void sendFile::send(QString path)
{// 创建一个QFile对象,将要发送的文件与该对象关联QFile file(path);QFileInfo info(path);// 创建一个QFileInfo对象,用于获取文件的元信息,如大小等file.open(QFile::ReadOnly); // 打开文件为只读模式int fileSize = info.size();// 获取文件的大小while(!file.atEnd())// 当文件未读到末尾时,循环读取文件{static int num = 0; // 定义一个静态变量num,用于累计已读取的字节数if(num == 0)// 如果是第一次读取,则发送文件的大小信息{tcp->write((char *)&fileSize, 4);// 将文件大小的前4个字节写入tcp套接字,以通知接收端文件的大小num = 4;// 将静态变量num设置为4,因为已经发送了文件大小的前4个字节}QByteArray line = file.readLine(); // 读取一行数据num += line.size();// 将读取的字节数累加到numint percent = (num * 100 / fileSize); // 计算已读取的字节数占总字节数的百分比tcp->write(line);// 将读取的数据行写入tcp套接字emit curpencent(percent);// 发射信号,通知界面文件传输的进度}
}

main.cpp

#include "mainwindow.h"
#include <QApplication>int main(int argc, char *argv[])
{QApplication a(argc, argv);MainWindow w;w.show();return a.exec();
}

这篇关于QT中通过TCP协议多线程的文件传输(客户端)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1098702

相关文章

嵌入式QT开发:构建高效智能的嵌入式系统

摘要: 本文深入探讨了嵌入式 QT 相关的各个方面。从 QT 框架的基础架构和核心概念出发,详细阐述了其在嵌入式环境中的优势与特点。文中分析了嵌入式 QT 的开发环境搭建过程,包括交叉编译工具链的配置等关键步骤。进一步探讨了嵌入式 QT 的界面设计与开发,涵盖了从基本控件的使用到复杂界面布局的构建。同时也深入研究了信号与槽机制在嵌入式系统中的应用,以及嵌入式 QT 与硬件设备的交互,包括输入输出设

【Linux】应用层http协议

一、HTTP协议 1.1 简要介绍一下HTTP        我们在网络的应用层中可以自己定义协议,但是,已经有大佬定义了一些现成的,非常好用的应用层协议,供我们直接使用,HTTP(超文本传输协议)就是其中之一。        在互联网世界中,HTTP(超文本传输协议)是一个至关重要的协议,他定义了客户端(如浏览器)与服务器之间如何进行通信,以交换或者传输超文本(比如HTML文档)。

多线程解析报表

假如有这样一个需求,当我们需要解析一个Excel里多个sheet的数据时,可以考虑使用多线程,每个线程解析一个sheet里的数据,等到所有的sheet都解析完之后,程序需要提示解析完成。 Way1 join import java.time.LocalTime;public class Main {public static void main(String[] args) thro

Java Websocket实例【服务端与客户端实现全双工通讯】

Java Websocket实例【服务端与客户端实现全双工通讯】 现很多网站为了实现即时通讯,所用的技术都是轮询(polling)。轮询是在特定的的时间间隔(如每1秒),由浏览器对服务器发 出HTTP request,然后由服务器返回最新的数据给客服端的浏览器。这种传统的HTTP request 的模式带来很明显的缺点 – 浏 览器需要不断的向服务器发出请求,然而HTTP

【Go】go连接clickhouse使用TCP协议

离开你是傻是对是错 是看破是软弱 这结果是爱是恨或者是什么 如果是种解脱 怎么会还有眷恋在我心窝 那么爱你为什么                      🎵 黄品源/莫文蔚《那么爱你为什么》 package mainimport ("context""fmt""log""time""github.com/ClickHouse/clickhouse-go/v2")func main(

Java 多线程概述

多线程技术概述   1.线程与进程 进程:内存中运行的应用程序,每个进程都拥有一个独立的内存空间。线程:是进程中的一个执行路径,共享一个内存空间,线程之间可以自由切换、并发执行,一个进程最少有一个线程,线程实际数是在进程基础之上的进一步划分,一个进程启动之后,进程之中的若干执行路径又可以划分成若干个线程 2.线程的调度 分时调度:所有线程轮流使用CPU的使用权,平均分配时间抢占式调度

Java 多线程的基本方式

Java 多线程的基本方式 基础实现两种方式: 通过实现Callable 接口方式(可得到返回值):

【QT】基础入门学习

文章目录 浅析Qt应用程序的主函数使用qDebug()函数常用快捷键Qt 编码风格信号槽连接模型实现方案 信号和槽的工作机制Qt对象树机制 浅析Qt应用程序的主函数 #include "mywindow.h"#include <QApplication>// 程序的入口int main(int argc, char *argv[]){// argc是命令行参数个数,argv是

2024.9.8 TCP/IP协议学习笔记

1.所谓的层就是数据交换的深度,电脑点对点就是单层,物理层,加上集线器还是物理层,加上交换机就变成链路层了,有地址表,路由器就到了第三层网络层,每个端口都有一个mac地址 2.A 给 C 发数据包,怎么知道是否要通过路由器转发呢?答案:子网 3.将源 IP 与目的 IP 分别同这个子网掩码进行与运算****,相等则是在一个子网,不相等就是在不同子网 4.A 如何知道,哪个设备是路由器?答案:在 A

Python QT实现A-star寻路算法

目录 1、界面使用方法 2、注意事项 3、补充说明 用Qt5搭建一个图形化测试寻路算法的测试环境。 1、界面使用方法 设定起点: 鼠标左键双击,设定红色的起点。左键双击设定起点,用红色标记。 设定终点: 鼠标右键双击,设定蓝色的终点。右键双击设定终点,用蓝色标记。 设置障碍点: 鼠标左键或者右键按着不放,拖动可以设置黑色的障碍点。按住左键或右键并拖动,设置一系列黑色障碍点