Qt implements tcp to send and receive files

serverwidget.h

#ifndef SERVERWIDGET_H
#define SERVERWIDGET_H
#ifdef WIN32
#pragma execution_character_set("utf-8")
#endif

#include <QWidget>
#include <QTcpServer>//监听套接字
#include <QTcpSocket>//通信套接字
#include <QFile>
#include<QTimer>
namespace Ui {
    
    
class serverWidget;
}
class serverWidget : public QWidget
{
    
    
    Q_OBJECT
public:
    explicit serverWidget(QWidget *parent = nullptr);
    ~serverWidget();
    void sendData();
private slots:
    void on_buttonFile_clicked();
    void on_buttonSend_clicked();
private:
    Ui::serverWidget *ui;
    QTcpServer *tcpServer;//监听套接字
    QTcpSocket *tcpSocket;//通信套接字
    QFile file;//文件对象
    QString fileName;//文件名字
    qint64 fileSize;//文件大小
    qint64 sendSize;//已经发送文件的大小

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

serverwidget.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->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(tcpSocket,&QTcpSocket::readAll,
                [=]()
                    {
    
    
                        //取出客户端信息
                        QByteArray buf = tcpSocket->readAll();
                        if(QString(buf) == "file done")
                        {
    
    
                            ui->textEdit->append("文件发送完毕");

                            file.close();
                            //断开客户端端口
                            tcpSocket->disconnectFromHost();
                            tcpSocket->close();
                        }
                    }

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

                    //发送文件
                    sendData();
                }
            );
}

serverWidget::~serverWidget()
{
    
    
    delete ui;
}
//选择文件按钮
void serverWidget::on_buttonFile_clicked()
{
    
    
    QString filePath = QFileDialog::getOpenFileName(this,"打开","../");
    //判断,如果打开的路径有效
    if(false == filePath.isEmpty())
    {
    
    
        fileName.clear();
        fileSize = 0 ;

        //获取文件信息
        QFileInfo info(filePath);
        fileName = info.fileName();//获取文件名字
        fileSize = info.size();//获取文件大小

        sendSize = 0 ; //已发送文件的大小,初始化为0

        //只读方式打开文件
        //指定文件的名字
        file.setFileName(filePath);
        //打开文件
        bool isOK = file.open(QIODevice::ReadOnly);
        if(false == isOK)
        {
    
    
            qDebug() << "只读方式打开文件失败 72";
        }

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

        ui->buttonFile->setEnabled(false);
        ui->buttonSend->setEnabled(true);
    }
    else
    {
    
    
        qDebug()<<"打开的路径错误:58";
    }
}
//发送文件按钮
void serverWidget::on_buttonSend_clicked()
{
    
    
    //先发送文件头信息   文件名##文件大小
    QString head = QString("%1##%2").arg(fileName).arg(fileSize);
    //发送头部信息
    qint64 len = tcpSocket->write( head.toUtf8() );
    if(len > 0)//如果头部信息发送成功
    {
    
    
        //发送真正的文件信息
        //防止TCP黏包文件,需要通过定时器延时20ms
        timer.start(20);
    }
    else
    {
    
    
        qDebug() << "头部文件发送失败 101";
        file.close();
        ui->buttonFile->setEnabled(true);
        ui->buttonSend->setEnabled(false);
    }
}

void serverWidget::sendData()
{
    
    
    qint64 len = 0;
    do
    {
    
    
        //每次发送数据的大小,4k
        char buf[4*1024] = {
    
    0};
        len= 0;

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

        //发送的数据累加
        sendSize += len;

    }while(len >0);
    if(sendSize == fileSize)
    {
    
    
        ui->textEdit->append("文件发送完毕");
        file.close();

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

clientwidget.h

#ifndef CLIENTWIDGET_H
#define CLIENTWIDGET_H
#ifdef WIN32
#pragma execution_character_set("utf-8")
#endif

#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 receiveSize;//已经收到文件的大小

    bool isStart;//定义一个标识位
};

#endif // CLIENTWIDGET_H

clientwidget.cpp

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

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

    tcpSocket = new QTcpSocket(this);
    isStart = true;

    //进度条设置当前值0
    ui->progressBar->setValue(0);

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

                        //解析头部信息,拆包,类似数组取下标的方式
                        //QString str = "hello##1024##mike"
                        //str.section("##",0,0)

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

                        //打开文件
                        file.setFileName(fileName);
                        bool isOK = file.open(QIODevice::WriteOnly);
                        if(false == isOK)
                        {
    
    
                            qDebug() << "WriteOnly error 38";
                        }

                        //弹出对话框,显示接收文件的信息
                        QString str1 = QString("接收的文件:[%1:%2kb]").arg(fileName).arg(fileSize/1024);
                        ui->textEdit->append(str1);
                        //QMessageBox::information(this,"文件信息",str1);

                        //设置进度条
                        ui->progressBar->setMinimum(0);//最小值
                        ui->progressBar->setMaximum(fileSize/1024);//最大值
                        ui->progressBar->setValue(0);//当前值

                    }
                    //读文件信息
                    else
                    {
    
    
                        qint64 len = file.write(buf);
                        receiveSize += len;

                        //客户端接收了多少,反馈给服务器
                        //QString str = QString::number(receiveSize);
                        //tcpSocket->write(str.toUtf8().data());

                        //更新进度条
                        ui->progressBar->setValue(receiveSize/1024);

                        if(receiveSize == fileSize)
                        {
    
    
                            //给服务器发送(接收文件完成)
                            //tcpSocket->write("file done");

                            file.close();
                            QMessageBox::information(this,"完成","文件接收完成");

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

Guess you like

Origin blog.csdn.net/weixin_40355471/article/details/110391887