QT之网络编程-文件传输

昨天我们写了QT之TCP网络编程,今天就来看一下,在QT下的文件传输,这是在昨天所写代码的基础上添加上的。。

先看一下最终效果:
在这里插入图片描述
在这里插入图片描述
文件传输主要步骤:
服务器端:
1、打开服务器端的文件所在路径

 QString filePath = QFileDialog::getOpenFileName(this,"选择文件","../");

2、打开文件

 bool isOK = file.open(QIODevice::ReadOnly);

3、先发送文件头部信息

//先发送文件头信息 文件名##文件大小
QString head = QString("%1##%2").arg(fileName).arg(fileSize);
//发送头部信息
qint64 len = tcpSocket->write(head.toUtf8());

4、发送真是的文件数据

//往文件里读数据
len = file.read(buf,sizeof(buf));
//发送数据,读多少,发多少
len = tcpSocket->write(buf,len);

客户端:
1、建立连接后收到服务器文件数据的信号槽

connect(tcpSocket,&QTcpSocket::readyRead,[=](){});

2、解析头部信息

 //解析头部信息,初始化
fileName = QString(buf).section("##",0,0);
fileSize = QString(buf).section("##",1,1).toInt();

3、打开文件

 bool isOK = file.open(QIODevice::WriteOnly|QIODevice::Append);

4、读取文件信息

quint64 len = file.write(buf);

这里还是贴一下源码吧,虽然可以实现传输文件功能,由于在网络编程基础上修改的,里边还存在一些bug,有兴趣的同学可以修改一下,使其完美一些.

不要忘记在.pro文件中添加 QT += core gui network

serverwidget.h

#ifndef SERVERWIDGET_H
#define SERVERWIDGET_H

#include <QWidget>
#include<QTcpServer>//监听套接字
#include<QTcpSocket>//通信套接字
#include<QFile>
#include<QTimer>

QT_BEGIN_NAMESPACE
namespace Ui { class ServerWidget; }
QT_END_NAMESPACE

class ServerWidget : public QWidget
{
    Q_OBJECT

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

    void sendData();//发送数据

private slots:
    void on_ButtonSend_clicked();
    void on_ButtonClose_clicked();

    void on_ButtonFile_clicked();
    void on_ButtonFileSend_clicked();

private:
    Ui::ServerWidget *ui;
    QTcpServer *tcpServer;//监听套接字
    QTcpSocket *tcpSocket;//通信套接字

    QFile file;//文件对象
    QString fileName;//文件名称
    quint64 fileSize;//文件大小
    quint64 sendSize;//已经发送文件大小
    QTimer timer;//定时器

};
#endif // SERVERWIDGET_H

serverwidget.cpp

#include "serverwidget.h"
#include "ui_serverwidget.h"
#include<QFileDialog>
#include<QMessageBox>
#include<QTimer>
#include<QFileInfo>

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

    //初始化套接字
    tcpServer = NULL;
    tcpSocket = NULL;

    //监听套接字,指定父对象自动回收空间
    tcpServer = new QTcpServer(this);
    //设定端口
    tcpServer->listen(QHostAddress::Any,8888);
    //新连接建立的信号槽
    connect(tcpServer,&QTcpServer::newConnection,[=](){
        //取出建立好连接的套接字
        tcpSocket = tcpServer->nextPendingConnection();
        //获取对方的ip和端口
        QString ip = tcpSocket->peerAddress().toString();
        qint16 port = tcpSocket->peerPort();

        //将信息显示到UI
        QString temp = QString("[%1:%2]: 连接成功").arg(ip).arg(port);
        ui->textEditRead->setText(temp);

        //连接建立后读取到数据的信号槽
        connect(tcpSocket,&QTcpSocket::readyRead,[=](){
            //从通信套接字取出内容
            QByteArray array = tcpSocket->readAll();
            //显示到UI
            ui->textEditRead->append(array);
        });
    });

    connect(&timer,&QTimer::timeout,[=](){
        //关闭定时器
        timer.stop();
        //发送文件
        sendData();
    });

    setWindowTitle("TCP服务器,端口:8888");
}

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

void ServerWidget::on_ButtonSend_clicked()
{
    if(NULL == tcpSocket)
    {
        return;
    }
    //获取编辑区内容
    QString str = ui->textEditWrite->toPlainText();
    //给对方发数据
    tcpSocket->write(str.toUtf8().data());
}
void ServerWidget::on_ButtonClose_clicked()
{
    if(NULL == tcpSocket)
    {
        return;
    }
    //主动和客户端断开连接
    tcpSocket->disconnectFromHost();
    //关闭套接字
    tcpSocket->close();
    tcpSocket = NULL;
}


//选择要发送的文件
void ServerWidget::on_ButtonFile_clicked()
{
    QString filePath = QFileDialog::getOpenFileName(this,"选择文件","../");
    //若文件路径无效。则提示
    if(filePath.isEmpty())
    {
        QMessageBox::information(this,"提示:",filePath+"文件路径无效");
        return ;
    }
    fileName.clear();
    fileSize=0;
    sendSize=0;
    //获取文件信息
    QFileInfo info(filePath);
    fileName = info.fileName();
    fileSize = info.size();

    //以只读方式打开
    //指定文件的名称
    file.setFileName(filePath);
    //打开文件
    bool isOK = file.open(QIODevice::ReadOnly);
    if(!isOK)
    {
        QMessageBox::information(this,"提示:","只读方式打开文件失败");
        return ;
    }

    //提示打开文件路径
    ui->textEditRead->append(filePath);
}


void ServerWidget::on_ButtonFileSend_clicked()
{
    //先发送文件头信息 文件名##文件大小
    QString head = QString("%1##%2").arg(fileName).arg(fileSize);
    //发送头部信息
    qint64 len = tcpSocket->write(head.toUtf8());
    //如果len>0,则头部信息发送成功
    if(len>0)
    {
        //发送真正的文件信息,为防止tcp黏包信息,定时器需要延时
        timer.start(20);
    }
    else
    {
        QMessageBox::information(this,"提示:","头部信息发送失败");
        file.close();
        return ;
    }

}

void ServerWidget::sendData()
{
    quint64 len = 0;
    do
    {
        //每次发送数据的大小
        char buf[1024] = {0};
        len=0;
        //往文件里读数据
        len = file.read(buf,sizeof(buf));
        //发送数据,读多少,发多少
        len = tcpSocket->write(buf,len);

        sendSize+=len;
    }while(len>0);
}

main.cpp 就不贴了,默认的就好(可以自己修改)。

clientwidget.h

#ifndef CLIENTWIDGET_H
#define CLIENTWIDGET_H

#include <QWidget>
#include <QTcpSocket>//通信套接字
#include <QFile>

QT_BEGIN_NAMESPACE
namespace Ui { class ClientWidget; }
QT_END_NAMESPACE

class ClientWidget : public QWidget
{
    Q_OBJECT

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

private slots:

    void on_buttonSend_clicked();
    void on_buttonClose_clicked();
    void on_ButtonConnect_clicked();

private:
    Ui::ClientWidget *ui;
    QTcpSocket *tcpSocket;

    QFile file;
    QString fileName;
    quint64 fileSize;//文件大小
    quint64 reciveSize;//已经接收文件大小

    bool isStart;
};
#endif // CLIENTWIDGET_H

clientwidget.cpp

#include "clientwidget.h"
#include "ui_clientwidget.h"
#include <QHostAddress>
#include <QDebug>
#include <QMessageBox>

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

    ui->progressBar->setValue(0);
    isStart = true;

    //初始化套接字
    tcpSocket = NULL;
    //分配空间,指定父对象
    tcpSocket = new QTcpSocket(this);
    //建立连接的信号槽
    connect(tcpSocket,&QTcpSocket::connected,[=](){
        ui->textEditRead->setText("恭喜,成功连接服务器");
    });

    //建立连接后收到服务器数据的信号槽
//    connect(tcpSocket,&QTcpSocket::readyRead,[=](){
//        //获取对方发送的数据
//        QByteArray array = tcpSocket->readAll();
//        ui->textEditRead->append(array);
//    });

    //建立连接后收到服务器文件数据的信号槽
    connect(tcpSocket,&QTcpSocket::readyRead,[=](){
        //获取对方发送的文件数据
        QByteArray buf = tcpSocket->readAll();
        if(isStart==true)
        {
            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|QIODevice::Append);
            if(isOK == false)
            {
//                tcpSocket->disconnectFromHost();
//                tcpSocket->close();
                QMessageBox::information(this,"提示:","打开文件错误");
//                return ;
            }

            //初始化进度条
            ui->progressBar->setMinimum(0);
            ui->progressBar->setMaximum(fileSize/1024);
            ui->progressBar->setValue(0);
        }

        else
        {
            //文件信息
            quint64 len = file.write(buf);
            if(len>0)
            {
                reciveSize+=len;
            }

            //更新进度条
            ui->progressBar->setValue(reciveSize/1024);
            if(reciveSize==fileSize)
            {
                //传输文件完毕
//                file.close();
                QMessageBox::information(this,"提示:","文件接收完毕");
//                tcpSocket->disconnectFromHost();
//                tcpSocket->close();
            }
        }
    });

    setWindowTitle(QString("TCP客户端"));
}

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

void ClientWidget::on_buttonSend_clicked()
{
    //获取编辑内容
    QString str = ui->textEditWrite->toPlainText();
    //发送数据
    tcpSocket->write(str.toUtf8().data());
}

void ClientWidget::on_buttonClose_clicked()
{
    tcpSocket->disconnectFromHost();
}

void ClientWidget::on_ButtonConnect_clicked()
{
    //获取服务器IP和端口
    QString ip = ui->lineEditIP->text();
    qint16 port = ui->lineEditPort->text().toInt();

    //主动连接服务器
    tcpSocket->connectToHost(QHostAddress(ip),port);
    ui->progressBar->setValue(0);
}
下载代码方式:https://pan.quark.cn/s/dd3561eca308 在软件开发领域,面向对象编程(OOP)是一种普遍采纳的结构化方法,它使得开发者能够借助模拟现实环境中的实体和关系来构建软件系统。在本案例中,我们观察到的是一个关于借助抽象类来执行不同几何图形面积求解的实践应用。现在,让我们详细分析这一议题。 标题 "应用抽象类计算面积" 清晰地表明我们将要讨论一个抽象类,此类设定了一个用于测量图形面积的标准函数,但并未提供实际的执行过程。抽象类在诸如C#或Java等编程语言中通常借助`abstract`修饰符进行声明,它们无法直接创建对象实例,仅能作为其他类的基础模板。 描述部分提及的"图形界面应用"暗示这是一个基于视觉用户界面(GUI)的系统,可能运用了.NET Framework的Windows Forms或WPF技术,或者是Java平台的Swing或JavaFX框架。在这样环境下,用户能够通过视觉元素这些几何体进行互动,例如输入相关尺寸并观看到计算得出的面积值。 抽象类“几何体”内嵌了“计算面积”这一抽象函数。在代码层面,这可以被表述为: ```csharp public abstract class GeometricShape { public abstract double CalculateArea(); } ``` 随后,有三个派生类:圆(Circle)、矩形(Rectangle)和三角形(Triangle),它们各自提供了这个抽象函数的具体实现。比如,圆的面积是通过π乘以半径的平方得到的,矩形的面积是长和宽的乘积,而三角形的面积可能是底乘以高再除以2的结果。这些类将提供具体实现来计算它们各自的面积: ```csharp p...
内容概要:本文系统研究了移相控制全桥LLC谐振变换器的工作特性,深入分析其在不同工作模式下的运行机理性能表现,重点探讨了软开关实现、高效率能量转换及宽范围电压调节等关键技术优势。通过Simulink搭建精确的仿真模型,对谐振腔参数、开关频率、电压增益、系统效率等关键指标进行仿真分析,验证了理论设计的正确性。同时,详细研究了移相控制策略对系统动态响应、稳定性和轻载/重载工况适应性的影响,揭示了控制参数电路参数之间的耦合关系,为高频高效电源设计提供了理论依据和实践指导。; 适合人群:具备电力电子技术、模拟电路及自动控制理论基础,从事开关电源、新能源变换器、电动汽车充电模块或高频电源系统研发的工程师及高校研究生。; 使用场景及目标:①掌握全桥LLC谐振变换器的拓扑结构、工作原理关键参数设计方法;②理解移相控制在实现零电压开通(ZVS)和零电流关断(ZCS)中的作用机制;③通过Simulink仿真掌握变换器建模、参数优化性能评估流程,服务于实际产品开发学术课题研究。; 阅读建议:建议读者结合提供的Simulink仿真模型进行同步操作,重点关注谐振网络(Lr, Lm, Cr)参数移相角之间的匹配设计,深入理解软开关条件的形成过程,并通过调整负载和输入电压进行多工况仿真,以全面掌握系统动态特性。
一、项目概述 本项目设计并实现了一个基于STM32F103C8T6微控制器的温湿度监测报警系统。系统通过DHT11传感器实时采集环境温湿度数据,当数据超过预设阈值时,蜂鸣器发出声音报警,同时通过4位数码管实时显示当前温湿度值。整个系统采用Type-C接口供电,支持USB串口通信,便于数据调试传输。 二、硬件组成 1. 主控模块:STM32F103C8T6最小系统(含晶振、复位、BOOT电路、去耦电容)。 2. 传感器模块:DHT11温湿度传感器(单总线通信)。 3. 报警模块:有源蜂鸣器(三极管驱动)。 4. 显示模块:4位共阴数码管(TM1637驱动)。 5. 通信模块:CH340N USB转串口芯片(Type-C接口)。 6. 电源模块:AMS1117-3.3稳压电路(5V转3.3V)。 7. 调试接口:SWD调试排针(SWDIO/SWCLK)。 三、开发流程 1. 原理图设计:使用嘉立创EDA绘制完整原理图,包含各功能模块。 2. PCB设计:进行PCB布局布线,注重电源完整性、信号隔离及晶振走线。 3. 制板焊接:嘉立创打样,手工焊接元器件。 4. 软件开发:STM32CubeMX配置工程,编写DHT11驱动、TM1637显示、串口通信及报警逻辑。 5. 调试测试:通过SWD下载程序,串口输出数据,测试温湿度采集报警功能。 四、项目特点 - 完整的嵌入式系统开发流程(硬件设计→制板→软件编程→调试)。 - 多传感器数据融合实时显示。 - 低功耗设计,支持USB供电串口通信。 - 模块化设计,便于功能扩展(如添加WiFi模块、数据存储等)。 五、应用前景 适用于家庭环境监测、农业大棚、仓库温湿度监控等场景
内容概要:本文提出了一种基于TOGI-SOGI混合积分器的光储并网谐波自适应抑制方法,并通过Simulink实现完整仿真验证。该方法融合三重二阶广义积分器(TOGI)标准二阶广义积分器(SOGI),能够精确提取电网电压中的基波正序分量,有效分离并抑制高次谐波成分,尤其在电网电压畸变条件下显著提升了并网逆变器的控制精度电能质量。文中详细阐述了混合积分器的结构设计、谐波检测机制、自适应调节策略及其在锁相环(PLL)中的集成应用,并通过构建光储并网系统模型进行多工况仿真,结果表明该方法具备优良的动态响应特性、强鲁棒性及谐波抑制能力。; 适合人群:具备电力电子、新能源发电、自动控制等相关专业背景,熟悉Simulink仿真环境,从事光伏并网控制、电能质量治理、微电网运行控制等领域研究的科研人员、工程技术人员及研究生。; 使用场景及目标:①应用于电网存在谐波污染的光伏发电并网场景,提升逆变器在非理想电网下的运行稳定性;②为基于广义积分器的先进锁相技术谐波补偿策略提供理论支持实现范例;③服务于高校科研项目复现、学位论文研究、电力电子控制器原型开发及学术成果验证。; 阅读建议:建议学习者结合提供的Simulink模型深入剖析TOGI-SOGI的内部信号流向参数整定逻辑,重点关注谐波分量的解耦过程自适应控制模块的实现机制,可通过设置不同谐波含量、频率偏移等扰动工况进行对比测试,以全面掌握其在复杂电网环境下的适应性优越性。
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值