Under the Qt framework TCP/IP protocol to transfer any type/size file source code

  • flow chart:

Insert picture description here

#ifndef CLIENTWIDGET_H
#define CLIENTWIDGET_H

#include <QWidget>
#include <QTcpSocket>
#include <QFile>
namespace Ui {
    
    
class ClientWidget;
}

class ClientWidget : public QWidget
{
    
    
    Q_OBJECT

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

private slots:
    void on_buttonConnect_clicked();

private:
    Ui::ClientWidget *ui;
    QTcpSocket *tcpSocket;
    QFile file;//文件对象
    QString fileName;//文件名字
    qint64 fileSize;//文件大小
    qint64 recvSize;//已经接收文件的大小
    bool isStart;//标志位,用于区别数据信息还是真实数据
};

#endif // CLIENTWIDGET_H
#ifndef SEVERWIDGET_H
#define SEVERWIDGET_H

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

QT_BEGIN_NAMESPACE
namespace Ui {
    
     class SeverWidget; }
QT_END_NAMESPACE

class SeverWidget : public QWidget
{
    
    
    Q_OBJECT

public:
    SeverWidget(QWidget *parent = nullptr);
    ~SeverWidget();
    void sendData();//发送文件数据

private slots:
    void on_buttonFile_clicked();

    void on_buttonSend_clicked();

private:
    Ui::SeverWidget *ui;
    QTcpServer *tcpServer;//监听套接字
    QTcpSocket *tcpSocket;//通信套接字
    QFile file;//文件对象
    QString fileName;//文件名字
    qint64 fileSize;//文件大小
    qint64 sendSize;//已经发送文件的大小
    QTimer timer;
};
#endif // SEVERWIDGET_H

#include "clientwidget.h"
#include "ui_clientwidget.h"
#include <QMessageBox>
#include <QHostAddress>
ClientWidget::ClientWidget(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::ClientWidget)
{
    
    
    ui->setupUi(this);
    tcpSocket = new QTcpSocket(this);
    isStart = true;
    ui->progressBar->setValue(0);//初始化进度条
    connect(tcpSocket,&QTcpSocket::readyRead,
    [=](){
    
    
            //取出接收的内容
        QByteArray buf = tcpSocket->readAll();
            if(true == isStart )
            {
    
    //解析头部信息
                isStart = false;
                fileName = QString(buf).section("##",0,0);//区分拆包信息 参数一:拆包的标识,参数二/三:从第零段开始到第零段结束,
                fileSize = QString(buf).section("##",1,1).toInt();
                //初始化
                recvSize = 0;
                //打开文件
                file.setFileName(fileName);
                file.open(QIODevice::WriteOnly);
                //设置进度条
                ui->progressBar->setMinimum(0);//最小值
                ui->progressBar->setMaximum(fileSize/1024);//最大值 qint64比int大,除1024除了转化为kb也可以防止进度条数值越界
                ui->progressBar->setValue(0);//当前值
            }
            else{
    
    //接收文件信息
                qint64 len = file.write(buf);
                recvSize += len;
                ui->progressBar->setValue(recvSize/1024);//更新进度条
                if(recvSize == fileSize)
                {
    
    
                    file.close();//关闭文件
                    QMessageBox::information(this,"完成","文件接收完成");
                }

            }
    }
            );
}

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

void ClientWidget::on_buttonConnect_clicked()
{
    
    
    //获取服务器IP和端口
    QString ip = ui->lineEditIP->text();
    quint16 port = ui->lineEditPort->text().toInt();
    tcpSocket->connectToHost(QHostAddress(ip),port);
}

#include "severwidget.h"
#include "ui_severwidget.h"
#include <QHostAddress>
#include <QFileDialog>
#include <QFileInfo>
SeverWidget::SeverWidget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::SeverWidget)
{
    
    
    ui->setupUi(this);
    //监听套接字
    tcpServer = new QTcpServer(this);
    //监听
    tcpServer->listen(QHostAddress::Any,8888);
    setWindowTitle("服务器端口:8888");
    //一开始两个按钮都不能按
    ui->buttonFile->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->buttonFile->setEnabled(true);

    }
            );
    connect(&timer,&QTimer::timeout,
            [=](){
    
    
        //进来先关定时器
        timer.stop();
        //发送文件
        sendData();
    }
            );
}
SeverWidget::~SeverWidget()
{
    
    
    delete ui;
}


void SeverWidget::on_buttonFile_clicked()//选择文件按钮
{
    
    
    QString filepath = QFileDialog::getOpenFileName(this,"open","../");//QFileDialog::getOpenFileName() 获取指定文件路径名返回QString
    if(false == filepath.isEmpty())//如果选择的文件路径有效
    {
    
    
        fileName.clear();//先把文件名字和文件大小清空
        fileSize = 0;
        //获取文件信息
        QFileInfo info(filepath);
        fileName = info.fileName();//获取文件名字
        fileSize = info.size();//获取文件大小
        sendSize = 0;//已经发送文件的大小
        //只读方式打开文件
        file.setFileName(filepath);
        file.open(QIODevice::ReadOnly);
        //提示一下打开文件的路径
        ui->textEdit->append(filepath);
        //设定一些按钮的状态
        ui->buttonFile->setEnabled(false);
        ui->buttonSend->setEnabled(true);
    }

}

void SeverWidget::on_buttonSend_clicked()//发送文件按钮
{
    
    
    //先发送文件头信息 文件名##文件大小
    QString head = QString("%1##%2").arg(fileName).arg(fileSize);
    qint64 len = tcpSocket->write(head.toUtf8());//Qstring.toutf8()即可转为QByteArray
    if(len > 0 )//头部信息发送成功
    {
    
    
        //发送真正的文件信息
          //防止TCP黏包问题 需要通过定时器延时 20ms
        timer.start(20);//保证头发了再发数据
    }
    else
    {
    
    
        file.close();//把之前打开的文件关了
        //恢复按钮
        ui->buttonFile->setEnabled(true);
        ui->buttonSend->setEnabled(false);
    }

}

void SeverWidget::sendData()
{
    
    
    qint64 len = 0;
    do
    {
    
    
        char buf[4*1024] = {
    
    0};//每次发4k
        len = 0;
        len = file.read(buf,sizeof(buf));//从文件中读数据,返回读取的字节数
        //发送数据,读多少发多少
        tcpSocket->write(buf,len);
        //发送的数据需要累加
        sendSize += len;
    }while(len > 0);//只要每次发送数据大于0就进来(当然有很多种方式)
    if(sendSize == fileSize)
    {
    
    
        ui->textEdit->append("文件发送完毕");
        file.close();
    }
}

Guess you like

Origin blog.csdn.net/qq_42308217/article/details/113574320