【QT】TCP 传文件 服务器与客户端

目录

1、效果流程

1.1 演示效果

1.2 TCP传文件流程图

2、项目结构

2.1 项目配置 TcpFile.pro

2.2 主函数入口 main.cpp

3、TCP文件服务器端

3.1 设计布局 serverwidget.ui

3.2 头文件 serverwidget.h

3.3 源文件 serverwidget.cpp

4、TCP文件客户端

4.1 设计布局 clientwidget.ui

4.2 头文件 clientwidget.h

4.3 源文件 clientwidget.cpp



1、效果流程

1.1 演示效果

1.2 TCP传文件流程图

 

2、项目结构

2.1 项目配置 TcpFile.pro

QT       += core gui network

greaterThan(QT_MAJOR_VERSION, 4): QT += widgets

CONFIG += c++11

# The following define makes your compiler emit warnings if you use
# any Qt feature that has been marked deprecated (the exact warnings
# depend on your compiler). Please consult the documentation of the
# deprecated API in order to know how to port your code away from it.
DEFINES += QT_DEPRECATED_WARNINGS

# You can also make your code fail to compile if it uses deprecated APIs.
# In order to do so, uncomment the following line.
# You can also select to disable deprecated APIs only up to a certain version of Qt.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000    # disables all the APIs deprecated before Qt 6.0.0

SOURCES += \
    clientwidget.cpp \
    main.cpp \
    serverwidget.cpp

HEADERS += \
    clientwidget.h \
    serverwidget.h

FORMS += \
    clientwidget.ui \
    serverwidget.ui

# Default rules for deployment.
qnx: target.path = /tmp/$${TARGET}/bin
else: unix:!android: target.path = /opt/$${TARGET}/bin
!isEmpty(target.path): INSTALLS += target

2.2 主函数入口 main.cpp

#include "serverwidget.h"
#include "clientwidget.h"

#include <QApplication>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    ServerWidget w;
    w.show();
    ClientWidget w2;
    w2.show();
    return a.exec();
}

3、TCP文件服务器端

3.1 设计布局 serverwidget.ui

3.2 头文件 serverwidget.h

#ifndef SERVERWIDGET_H
#define SERVERWIDGET_H

#include <QWidget>
#include <QTcpServer>
#include <QTcpSocket>
#include <QFile>
#include <QFileInfo>
#include <QFileDialog>
#include <QTimer>
//DEBUG
#include <QtDebug>
#define cout    qDebug()<<"["<<__FILE__<<":"<<__LINE__<<__TIME__<<"] "

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_btnFile_clicked();
    //发送文件按钮
    void on_btnSend_clicked();

private:
    Ui::ServerWidget *ui;

    /*--------funtion----------*/
    void systemInit();
    void sendData();

    /*--------variable---------*/
    QTcpServer *tcpServer;
    QTcpSocket *tcpSocket;

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

    QTimer *timer;      //启动发送真正数据定时器

};
#endif // SERVERWIDGET_H

3.3 源文件 serverwidget.cpp

#include "serverwidget.h"
#include "ui_serverwidget.h"

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

    /*------user-------*/
    systemInit();
}

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


/*------------------------------------------
 *              funtion
 *------------------------------------------*/
//用户系统初始化
void ServerWidget::systemInit()
{
    tcpServer = NULL;
    tcpSocket = NULL;
    timer = new QTimer(this);

    tcpServer = new QTcpServer(this);
    tcpServer->listen(QHostAddress::Any,8888);
    setWindowTitle("TCP服务器:8888");

    ui->btnFile->setEnabled(false);
    ui->btnSend->setEnabled(false);

    connect(tcpServer,&QTcpServer::newConnection,[=](){
        tcpSocket = tcpServer->nextPendingConnection();
        QString ip = tcpSocket->peerAddress().toString();
        quint16 port = tcpSocket->peerPort();
        //cout << ip << port;
        QString str = QString("[%1:%2] 成功连接").arg(ip).arg(port);
        ui->textBrowser->append(str);
        ui->btnFile->setEnabled(true);
    });

    connect(timer,&QTimer::timeout,[=](){
        timer->stop();
        sendData();
    });

}

void ServerWidget::sendData()
{
    qint64 len = 0;

    ui->textBrowser->append("文件正在发送中...");

    do{
        len = 0;
        //每次发送的数据量4K
        char buf[4*1024] = {0};
        //读取文件中数据
        len = file.read(buf,sizeof(buf));
        //读取多少数据  发送多少数据
        len = tcpSocket->write(buf,len);
        //发送数据量累积
        sendSize += len;
    }while(len > 0);

    if(file.size() == sendSize){
        ui->textBrowser->append("文件发送完成");
        file.close();
        ui->btnFile->setEnabled(false);
        ui->btnSend->setEnabled(false);
        tcpSocket->disconnectFromHost();
        tcpSocket->close();
    }
}

/*------------------------------------------
 *              slots
 *------------------------------------------*/
//选择文件按钮
void ServerWidget::on_btnFile_clicked()
{
    QString filePath = QFileDialog::getOpenFileName(this,"open","../");
    //cout << filePath;
    if(!filePath.isEmpty()){
        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){
            ui->textBrowser->append(filePath);
            ui->btnFile->setEnabled(false);
            ui->btnSend->setEnabled(true);
        }else{
            cout << "只读方式打开文件失败";
        }
    }else{
        cout << "选择文件路径出错";
    }
}
//发送文件按钮
void ServerWidget::on_btnSend_clicked()
{
    //发送文件头信息
    QString head = QString("head##%1##%2").arg(fileName).arg(fileSize);
    qint64 len = tcpSocket->write(head.toUtf8());
    if(len > 0){
        //发送真正的文件信息 
        timer->start(20);

    }else{
        cout << "头信息发送失败";
        ui->btnFile->setEnabled(false);
        ui->btnSend->setEnabled(false);
        file.close();
    }

}

4、TCP文件客户端

4.1 设计布局 clientwidget.ui

4.2 头文件 clientwidget.h

#ifndef CLIENTWIDGET_H
#define CLIENTWIDGET_H

#include <QWidget>
#include <QTcpSocket>
#include <QHostAddress>
#include <QFile>
#include <QMessageBox>

#include <QtDebug>
#define cout    qDebug()<<"["<<__FILE__<<":"<<__LINE__<<__TIME__<<"] "

namespace Ui {
class ClientWidget;
}

class ClientWidget : public QWidget
{
    Q_OBJECT

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

private slots:
    void on_btnConnect_clicked();

    void on_btnClose_clicked();

private:
    Ui::ClientWidget *ui;

    /*--------funtion----------*/
    void systemInit();

    /*--------variable---------*/
    QTcpSocket *tcpSocket;

    QFile file;         //文件对象
    QString fileName;   //文件名字
    qint64 fileSize;    //文件大小
    qint64 recvSize;    //已接收文件大小

    bool isStart;       //消息头标志
};

#endif // CLIENTWIDGET_H

4.3 源文件 clientwidget.cpp

#include "clientwidget.h"
#include "ui_clientwidget.h"

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

    /*-------user------*/
    systemInit();
}

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


/*------------------------------------------
 *              funtion
 *------------------------------------------*/
//用户系统初始化
void ClientWidget::systemInit()
{
    tcpSocket = new QTcpSocket(this);
    setWindowTitle("TCP客户端");

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

    connect(tcpSocket,&QTcpSocket::connected,[=](){
        ui->textBrowser->append("与服务器成功建立连接");
    });

    connect(tcpSocket,&QTcpSocket::disconnected,[=](){
        ui->textBrowser->append("与服务器已经断开连接");
    });

    connect(tcpSocket,&QTcpSocket::readyRead,[=](){
        //取出接收的内容
        QByteArray buf = tcpSocket->readAll();

        if(isStart){    //消息头接收
            //解析头部信息   初始化
            QString head = QString(buf).section("##",0,0);
            fileName = QString(buf).section("##",1,1);
            fileSize = QString(buf).section("##",2,2).toInt();
            recvSize = 0;

            if(head == "head"){
                //打开文件
                file.setFileName(fileName);
                bool isOk = file.open(QIODevice::WriteOnly);
                if(!isOk){
                    cout << "只读方式打开文件失败";
                     ui->textBrowser->append("只读方式打开文件失败");
                }else{
                    isStart = false;
                    ui->progressBar->setMinimum(0);
                    ui->progressBar->setMaximum(fileSize/1024);
                }
            }else{
                cout << "接收错误头部信息";
                ui->textBrowser->append("收错误头部信息");
                tcpSocket->disconnectFromHost();
                tcpSocket->close();
            }
        }else{  //文件信息接收
            qint64 len = file.write(buf);
            recvSize += len;
            ui->progressBar->setValue(recvSize/1024);
            if(fileSize == recvSize){
                file.close();
                QMessageBox::information(this,"完成","文件接收完成!");
                ui->textBrowser->append("文件接收完成!");
                tcpSocket->disconnectFromHost();
                tcpSocket->close();
            }
        }
    });


}

/*------------------------------------------
 *              slots
 *------------------------------------------*/
//connect 连接按钮
void ClientWidget::on_btnConnect_clicked()
{
    QString ip = ui->lineEditIP->text();
    quint16 port = ui->lineEditPort->text().toUInt();

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

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

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值