QT_使用TCP/IP传输文件

首选预览一下最终实现的效果,如下图:

QQ截图20180915235458.jpg


一、服务器端

1、widget.h

#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>

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

namespace Ui {
class Widget;
}

class Widget : public QWidget
{
    Q_OBJECT

public:
    explicit Widget(QWidget *parent = 0);
    ~Widget();

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

private slots:
    void on_buttonFile_clicked();

    void on_buttonSend_clicked();

private:
    Ui::Widget *ui;

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

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

};

#endif // WIDGET_H

2、widget.cpp

#include "widget.h"
#include "ui_widget.h"

#include <QHostAddress>
#include <QFileDialog>
#include <QMessageBox>
#include <QFileInfo>
#include <QDebug>

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

    setWindowTitle("服务器端口:8899");
    //禁用两个按钮
    ui->buttonFile->setEnabled(false);
    ui->buttonSend->setEnabled(false);
    //监听套接字
    tcpServer = new QTcpServer(this);
    //监听
    tcpServer->listen(QHostAddress::Any, 8899);

    //如果客户端成功与服务器连接
    //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();
    });
}

Widget::~Widget()
{
    delete ui;
}
//选择文件
void Widget::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->textEdit->append(filePath);

    ui->buttonFile->setEnabled(false);
    ui->buttonSend->setEnabled(true);


}
//发送文件
void Widget::on_buttonSend_clicked()
{
    //先发送文件头信息  文件名##文件大小
    QString head = QString("%1##%2").arg(fileName).arg(fileSize);
    //发送头部信息
    qint64 len = tcpSocket->write(head.toUtf8());
    //如果len大于0,则头部信息发送成功
    if(len > 0){
        //发送真正 的文件信息
        //防止tcp黏包信息
        //需要通过定时器延时20毫秒
        timer.start(20);
    }else{
        QMessageBox::information(this, "提示","头部信息发送失败");
        file.close();
        ui->buttonFile->setEnabled(true);
        ui->buttonSend->setEnabled(false);
        return ;
    }
}
// 发送文件数据
void Widget::sendData()
{
    ui->buttonFile->setEnabled(false);
    ui->buttonSend->setEnabled(false);
    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);
    //判断是否发送文件完毕
    /*if(sendSize == fileSize){
        QMessageBox::information(this, "提示","文件发送完毕");
        ui->textEdit->append("文件发送完毕");
        file.close();
        //把客户端断开
        tcpSocket->disconnectFromHost();
        ui->buttonFile->setEnabled(true);
        ui->buttonSend->setEnabled(false);
        return ;
    }*/
}


二、客户端

1、clientwidget.h

#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 = 0);
    ~ClientWidget();

private slots:
    void on_buttonConnect_clicked();

private:
    Ui::ClientWidget *ui;

    QTcpSocket *tcpSocket;

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

    bool isStart;
};

#endif // CLIENTWIDGET_H

2、clientwidget.cpp

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

#include <QMessageBox>
#include <QHostAddress>

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

    setWindowTitle("客户端");
    ui->progressBar->setValue(0);
    isStart = true;

    tcpSocket = new QTcpSocket(this);
    connect(tcpSocket, &QTcpSocket::readyRead,[=](){
        //取现接收的内容
        QByteArray buf = tcpSocket->readAll();
        if(isStart == true){
            isStart = false;
            //解析问部信息  buf = "hello##1024"
            //QString str = "hello##1024";   str.section("##",0,0);
            //初始化
            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->buttonConnect->setEnabled(false);
            //初始化进度条
            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, "提示", "文件接收完毕");
                ui->buttonConnect->setEnabled(true);
                tcpSocket->disconnectFromHost();
                tcpSocket->close();
            }
        }
    });
}

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

    ui->progressBar->setValue(0);
}


版权声明: 此文为本站源创文章[或由本站编辑从网络整理改编],
转载请备注出处:
[狂码一生] https://www.sindsun.com/articles/16/87
[若此文确切存在侵权,请联系本站管理员进行删除!]


--THE END--