Qt学习记录(十五)TCP传文件

目录

前言

TCP传文件

服务器端

UI

.pro工程文件

.h头文件

.cpp文件

客户端

UI

.h头文件

.cpp文件

现象


前言

猫看了都僵直

TCP传文件

服务器端

UI

.pro工程文件

QT       += core gui network
CONFIG+=C++11

.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();

private slots:
    void on_ButtonsFile_clicked();

    void on_ButtonSend_clicked();
    void sendData();//发送文件数据

private:
    Ui::ServerWidget *ui;

    QTcpServer *tcpServer;//监听套接字
    QTcpSocket *tcpSocket;//通信套接字

    QFile File;//文件对象
    QString fileName;//文件名字
    qint64 fileSize;//文件大小
    qint64 sendSize;//已经发送文件的大小

    QTimer timer;//定时器
};
#endif // SERVERWIDGET_H

.cpp文件

#include "serverwidget.h"
#include "ui_serverwidget.h"
#include <QFileDialog>
#include <QDebug>
#include <QFileInfo>


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

    tcpServer = new QTcpServer(this);//监听套接字

    //监听
    tcpServer->listen(QHostAddress::Any,8888);
    setWindowTitle("服务器端口为:8888");

    //两个按钮都不能按
    ui->ButtonsFile->setEnabled(false);
    ui->ButtonSend->setEnabled(false);
    //如果客户端成功和服务器连接
    //tcpServer 会自动触发,newConnection()
    connect(tcpServer, &QTcpServer::newConnection,
            [=]()
    {
        //取出建立好连接的套接字
        tcpSocket = tcpServer->nextPendingConnection();
        //获取对方的ip和端口
        QString ip = tcpSocket->peerAddress().toString();
        quint16 port=tcpSocket->peerPort();

        QString str = QString("[%1:%2]连接成功").arg(ip).arg(port);
        ui->textEdit->setText(str);//显示到编辑区

        //成功连接后,才能按选择文件
        ui->ButtonsFile->setEnabled(true);
        ui->ButtonSend->setEnabled(true);
    });

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

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

//选择文件按钮
void ServerWidget::on_ButtonsFile_clicked()
{
    QString filePath=QFileDialog::getOpenFileName(this,"open","../");
    if(false == filePath.isEmpty())//如果选择文件路径有效
    {
        fileName.clear();
        fileSize = 0;
        //获取文件信息
        QFileInfo info(filePath);
        fileName =info.fileName();//获取文件名字
        fileSize =info.size();//获取文件大小

        sendSize = 0;//发送文件的大小

        //只读方式打开文件
        //指定文件的名字
        File.setFileName(filePath);

        //打开文件
        bool isOK = File.open(QIODevice::ReadOnly);
        if(false == isOK)
        {
            qDebug() <<"只读方式打开文件失败 77";
        }
        //提示打开文件的路径
        ui->textEdit->append(filePath);

        ui->ButtonsFile->setEnabled(true);
        ui->ButtonSend->setEnabled(true);
    }
    else
    {
        qDebug()<<"选择文件路径出错,62";
    }
}
//发送文件按钮
void ServerWidget::on_ButtonSend_clicked()
{
    qDebug()<<"按下发送按键";
    //先发送文件头信息  文件名##文件大小
    QString head = QString ("%1##%2").arg(fileName).arg(fileSize);
    qDebug()<<"head:"<<head;
    //发送文件头信息
    qint64 len = tcpSocket->write(head.toUtf8());
    qDebug()<<"len:"<<len;
    if(len>0)//头信息发送成功
    {
     //发送真正的文件信息
     //防止Tcp粘包文件
     //需要定时器延时20ms
        timer.start(20);
        qDebug()<<"timer.start(20);";
    }
    else
    {
        qDebug()<<"头信息发送失败 105";
        File.close();
        ui->ButtonsFile->setEnabled(true);
        ui->ButtonSend->setEnabled(false);
    }

}
//发送文件数据
void ServerWidget::sendData()
{
    qDebug()<<"发送文件数据,sendData:";
    qint64 len =0;
    do
    {
        //每次发送数据的大小
        char buf[4*1024]={0};
        len=0;

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

        //发送的数据需要累积
        sendSize += len;
        qDebug()<<len;
    }while(len>0);
    //是否发送文件完毕
    if(sendSize == fileSize)
    {
        ui->textEdit->append("文件发送完毕");
        File.close();

        //把客户端端口
        tcpSocket->disconnectFromHost();
        tcpSocket->close();
    }
}

客户端

UI

.h头文件

#ifndef CLIENTWIDEGT_H
#define CLIENTWIDEGT_H

#include <QWidget>
#include <QTcpSocket>
#include <QFile>

namespace Ui {
class ClientWidegt;
}

class ClientWidegt : public QWidget
{
    Q_OBJECT

public:
    explicit ClientWidegt(QWidget *parent = nullptr);
    ~ClientWidegt();

private slots:
    void on_pushButton_clicked();

private:
    Ui::ClientWidegt *ui;
    QTcpSocket *tcpSocket;//通信套接字

    QFile File;//文件对象
    QString fileName;//文件名字
    qint64 fileSize;//文件大小
    qint64 recvSize;//已经接收文件的大小
};

#endif // CLIENTWIDEGT_H

.cpp文件

#include "clientwidegt.h"
#include "ui_clientwidegt.h"
#include <QDebug>
#include <QMessageBox>
#include <QHostAddress>

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

    tcpSocket = new QTcpSocket(this);

    bool isStart =true;
    connect(tcpSocket,&QTcpSocket::readyRead,
             [&]()
    {
       //取出接受的内容
        QByteArray buf=tcpSocket->readAll();
        if(true == isStart)
        {//接受头
            isStart = false;
            //解析头部信息 QString buf = "hello##1024"
//            QString str ="hello##1024#Dante";
//            str.section("##",0,0);

            //初始化
            fileName = QString(buf).section("##",0,0);
            fileSize = QString(buf).section("##",1,1).toInt();
            recvSize = 0;

            //打开文件
            File.setFileName(fileName);
            qDebug()<<"客户端接收到头文件fileName:"<<fileName<<fileSize;
            bool isOK=File.open(QIODevice::WriteOnly);
            if(false == isOK)
            {
                qDebug()<<"WriteOnly error 35";
            }
        }
        else if(false == isStart)//文件信息
        {

            qint64 len = File.write(buf);
            recvSize += len;

            if(recvSize == fileSize)
            {
               File.close();
               QMessageBox::information(this,"完成","文件接收完成");
               tcpSocket->disconnectFromHost();
               tcpSocket->close();
            }
        }
    });
}

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

void ClientWidegt::on_pushButton_clicked()
{
    //获取服务器ip和端口
    QString ip=ui->lineEditIP->text();
    quint16 port =ui->lineEdit_2->text().toUInt();

    tcpSocket->connectToHost(QHostAddress(ip),port);
}

现象

代码里面有很多莫名奇妙的打印,那个是我用来检查那一部分出问题的

后面搞着搞着莫名奇妙就能用了,==😓

绑定进度条

QProgressBar类的公共函数列表

*   QProgressBar(QWidget \\\*parent = nullptr):构造函数,创建一个新的QProgressBar对象,父对象为parent。
*   virtual \\~QProgressBar():析构函数,销毁QProgressBar对象。
*   Qt::Alignment alignment() const:获取进度条当前的对齐方式。
*   QString format() const:获取进度条当前的显示格式。
*   bool invertedAppearance() const:获取进度条是否反转外观。
*   bool isTextVisible() const:获取进度条上是否显示文本。
*   int maximum() const:获取进度条的最大值。
*   int minimum() const:获取进度条的最小值。
*   Qt::Orientation orientation() const:获取进度条的方向。
*   void resetFormat():重置进度条的显示格式。
*   void setAlignment(Qt::Alignment alignment):设置进度条的对齐方式。
*   void setFormat(const QString &format):设置进度条的显示格式。
*   void setInvertedAppearance(bool invert):设置进度条的外观是否反转。
*   void setTextDirection(QProgressBar::Direction textDirection):设置进度条上文本的方向。
*   void setTextVisible(bool visible):设置进度条上是否显示文本。
*   virtual QString text() const:获取进度条上显示的文本。
*   QProgressBar::Direction textDirection() const:获取进度条上文本的方向。
*   int value() const:获取进度条当前的进度值。

这些函数中,有些是获取器(getter)函数,只读取对象的属性值,例如minimum()、maximum()、orientation()等;有些是设置器(setter)函数,设置对象的属性值,例如setAlignment()、setFormat()、setTextDirection()等;还有一些是实现特定功能的函数,例如resetFormat()、setTextVisible()等。

 

 不作演示

  • 8
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值