Qt-socket网络 - tcp文件传输 进阶

待完善

done逻辑
datastream &file binary
传图片 Qbuffer

服务端

widget.h

#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>
#include <QTcpServer>
#include <QTcpSocket>
#include <QHostAddress>
#include <QString>
#include <QFile>
#include <QFileInfo>

QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE

class Widget : public QWidget
{
    Q_OBJECT

public:
    Widget(QWidget *parent = nullptr);
    ~Widget();

private slots:
    void on_pushButton_clicked();
    void myGetNewConnect();
    void myGetNewRead();
    void myDisconnected();

    void on_pushButton_2_clicked();

private:
    Ui::Widget *ui;
    QTcpServer *servSock;
    QTcpSocket *listenSock;
    QHostAddress servAddress;
    quint64 servPort;
    QString servSockInfo;
    QString clientSockInfo;

    bool isHead;
    QFile file;
    qint64 fileSize;
    QString fileName;
    qint64 fileNameSize;
    qint64 dataReadBytes;
    qint64 dataHeadReadBytes;

    void setFileInfo();
    qint64 BToLittleEndian(qint64 num);
    void BToLittleEndianFromByteArray(QByteArray &arr);

};
#endif // WIDGET_H

widget.cpp

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

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

    ui->lineEdit->setText("127.0.0.1");
    ui->lineEdit_2->setText("8080");

    ui->pushButton_2->setEnabled(false);

    ui->progressBar->setMinimum(0);
    ui->progressBar->setMaximum(1024);
    ui->progressBar->setValue(0);

    servSockInfo=QString("%1:%2").arg(ui->lineEdit->text(),ui->lineEdit_2->text());

    servSock=new QTcpServer(this);
    listenSock=new QTcpSocket(this);

    servAddress=QHostAddress(ui->lineEdit->text());
    servPort=ui->lineEdit_2->text().toUInt();

    isHead=true;
    fileNameSize=0;
    fileSize=0;
    dataHeadReadBytes=0;
    dataReadBytes=0;
}

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


void Widget::on_pushButton_clicked()
{

    if (!servSock->listen(servAddress,servPort))
    {
        ui->textEdit->append("ERROR: server listen failed...");
        ui->textEdit->append(servSock->errorString());
        return;
    }
    connect(servSock,&QTcpServer::newConnection,this,&Widget::myGetNewConnect);
    ui->textEdit->append("server listening... waiting a connect...");

    ui->pushButton->setEnabled(false);
    ui->pushButton_2->setEnabled(true);
}


void Widget::myGetNewConnect()
{
    listenSock=servSock->nextPendingConnection();
    if (listenSock->isValid() && listenSock->isOpen())
    {
        ui->lineEdit_3->setText(listenSock->peerAddress().toString());
        ui->lineEdit_4->setText(QString::number(listenSock->peerPort()));

        clientSockInfo=QString("%1:%2").arg(ui->lineEdit_3->text(),ui->lineEdit_4->text());

        ui->textEdit->append(QString("receive a new connect request: [ %1 -> %2 ]").arg(servSockInfo,clientSockInfo));

        connect(listenSock,&QTcpSocket::readyRead,this,&Widget::myGetNewRead);
        connect(listenSock,&QTcpSocket::disconnected,this,&Widget::myDisconnected);

        listenSock->write("connect server success...");

    }
}

void Widget::myGetNewRead()
{
    /* version 1 */
    if (isHead)
    {
        if (listenSock->bytesAvailable()>=sizeof(qint64) &&
                fileNameSize==0)
        {
            QByteArray fileNameSizeArray=listenSock->read(sizeof(qint64));
            memcpy(&fileNameSize,fileNameSizeArray.data(),fileNameSizeArray.size());
            fileNameSize=BToLittleEndian(fileNameSize);
            dataHeadReadBytes+=sizeof(qint64);
        }
        if (listenSock->bytesAvailable()>=fileNameSize &&
                fileNameSize!=0)
        {
            QByteArray fileName_temp;
            qint32 fileNameSize_temp;
            QByteArray fileNameSize_temp_arr;
            fileName_temp=listenSock->read(fileNameSize+4);
            fileNameSize_temp_arr=fileName_temp.first(4);
            BToLittleEndianFromByteArray(fileNameSize_temp_arr);
            memcpy(&fileNameSize_temp,fileNameSize_temp_arr.data(),4);

            if(fileNameSize==fileNameSize_temp)
            {
                fileName=QString(fileName_temp.mid(4));
            }
            else
            {
                ui->textEdit->append("ERROR: parse the head data with fileName failed");
                return;
            }
            dataHeadReadBytes+=(fileNameSize+4);

            if (fileName.isEmpty())
            {
                ui->textEdit->append("ERROR: receive head data failed");
                return ;
            }

        }
        if (fileSize==0 && dataHeadReadBytes>sizeof(qint64) && fileNameSize!=0 &&
                listenSock->bytesAvailable()>=sizeof(qint64))
        {
            QByteArray fileSizeArray=listenSock->read(sizeof(qint64));
            memcpy(&fileSize,fileSizeArray.data(),fileSizeArray.size());
            fileSize=BToLittleEndian(fileSize);
            dataHeadReadBytes+=sizeof(qint64);

            this->setFileInfo();

            isHead=false;
        }
        else
        {
            return ;
        }
    }
    else
    {
        if (dataReadBytes<=fileSize)
        {
            qint64 dataSize=0;
            QByteArray dataArray=listenSock->readAll();
            if (!dataArray.isEmpty())
            {
                dataSize=file.write(dataArray);
                if (dataSize>0)
                {
                    dataReadBytes+=dataSize;

                    ui->progressBar->setValue(dataReadBytes/1024);
                }
                if (dataReadBytes==fileSize)
                {
                    ui->textEdit->append("receive data and write done...");
                    file.close();
                    ui->textEdit->append("close the file");
                }

            }
        }
    }
}

void Widget::setFileInfo()
{
    ui->textEdit->append("receive file head info:");
    ui->textEdit->append("-- file name: "+fileName);
    ui->textEdit->append("-- file size: "+QString::number(fileSize));

    ui->textEdit->append("create a file ing...");

    file.setFileName(fileName);
    if (!file.open(QIODevice::WriteOnly))
    {
        ui->textEdit->append("ERROR: open file failed");
    }
    ui->textEdit->append("writing data to file...");
    ui->progressBar->setMaximum(fileSize/1024);
}


void Widget::myDisconnected()
{

}

void Widget::on_pushButton_2_clicked()
{
    listenSock->close();
    servSock->close();
}

qint64 Widget::BToLittleEndian(qint64 num)
{
    qint64 num_littleEnidan;
    num_littleEnidan=((num & 0x00000000000000FF)<<(7*8) | (num & 0x000000000000FF00)<<(5*8) |
                      (num & 0x0000000000FF0000)<<(3*8) | (num & 0x00000000FF000000)<<(1*8) |
                      (num & 0x000000FF00000000)>>(1*8) | (num & 0x0000FF0000000000)>>(3*8) |
                      (num & 0x00FF000000000000)>>(5*8) | (num & 0xFF00000000000000)>>(7*8));

    return num_littleEnidan;
}

void Widget::BToLittleEndianFromByteArray(QByteArray &arr)
{
    QByteArray arr_temp=arr;
    qint64 arrSize=arr.size();
    for (int i=0;i<arrSize;i++)
    {
        arr[i]=arr_temp[arrSize-1-i];
    }
}

.ui

在这里插入图片描述

客户端

widget.h

#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>
#include <QTcpServer>
#include <QTcpSocket>
#include <QHostAddress>
#include <QHostInfo>
#include <QFileDialog>
#include <QFile>
#include <QDebug>
#include <QString>
#include <QDataStream>
#include <QTimer>

QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE

class Widget : public QWidget
{
    Q_OBJECT

public:
    Widget(QWidget *parent = nullptr);
    ~Widget();

private slots:
    void on_pushButton_clicked();

    void on_pushButton_3_clicked();

    void myGetNewRead();

    void on_pushButton_2_clicked();

    void dataContinueSend();
    void myDisconnected();

private:
    Ui::Widget *ui;
    QTcpSocket *clientSock;
    QHostAddress servAddress;
    quint16 servPort;
    QString info;
    QFile file;
    QFileInfo fileInfo;
    QTimer *myTimer;
    qint64 fileSize;

    QByteArray dataArray;
};

#define sendBufferSize 512
#endif // WIDGET_H

widget.cpp

#include "widget.h"
#include "ui_widget.h"
#include <QProgressBar>

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

    setWindowTitle("client");
    this->resize(720,570);

    ui->lineEdit->setText("127.0.0.1");
    ui->lineEdit_2->setText("8080");

    ui->pushButton_2->setEnabled(false);
//    ui->pushButton_3->setEnabled(false);
    ui->progressBar->setValue(0);

    clientSock=new QTcpSocket(this);
    servAddress=QHostAddress(ui->lineEdit->text());
    servPort=ui->lineEdit_2->text().toUInt();

    info=QString("%1:%2").arg(ui->lineEdit->text(),ui->lineEdit_2->text());

    connect(clientSock,&QTcpSocket::readyRead,this,&Widget::myGetNewRead);
    connect(clientSock,&QTcpSocket::bytesWritten,this,&Widget::dataContinueSend);
    connect(clientSock,&QTcpSocket::disconnected,this,&Widget::myDisconnected);

    dataArray.resize(sendBufferSize);

}

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


void Widget::on_pushButton_clicked()
{
    clientSock->abort(); // 取消之前所有的连接,且抛弃所有缓冲区的内容

    clientSock->connectToHost(servAddress,servPort);
    if (!clientSock->waitForConnected(10000))
    {
        ui->textEdit->append("ERROR: connect failed...");
        return;
    }
    if (!clientSock->isValid())
    {
        ui->textEdit->append("ERROR: the socket is invalid...");
    }
    ui->textEdit->append("connect server "+info);

    ui->pushButton->setEnabled(false); // connect
    ui->pushButton_3->setEnabled(true); // openfile
}


void Widget::on_pushButton_3_clicked()
{
    QString fileName=QFileDialog::getOpenFileName(this,"打开文件","./");

    if (fileName.isEmpty())
    {
        ui->textEdit->append("ERROR: connot find file");
        return;
    }

    fileInfo=QFileInfo(fileName);
    fileSize=fileInfo.size();

    ui->lineEdit_3->setText(fileInfo.absoluteFilePath());
    ui->progressBar->setMaximum(fileSize/512);

    file.setFileName(fileInfo.absoluteFilePath());
    if (!file.open(QIODevice::ReadOnly))
    {
        ui->textEdit->append("ERROR: file open failed...");
        return ;
    }

    ui->textEdit->append("ready to send file info:");
    ui->textEdit->append("-- file name: "+fileInfo.fileName());
    ui->textEdit->append("-- file size: "+QString::number(fileSize)+" bytes");

    ui->progressBar->setMinimum(0);
    ui->progressBar->setMaximum(fileSize/1024);


    ui->pushButton_3->setEnabled(false);
    ui->pushButton_2->setEnabled(true);
}

void Widget::myGetNewRead()
{
    QByteArray readArray=clientSock->readAll();
    if (!readArray.isEmpty())
    {
        ui->textEdit->append(QString("receive from server %1:").arg(info));
        ui->textEdit->append(readArray);
    }

    if (QString(readArray)=="done")
    {
        ui->textEdit->append("server receive done...");
        ui->textEdit->append("close client...");
        clientSock->disconnectFromHost();
    }

}

void Widget::on_pushButton_2_clicked()
{
    // 以数据流的方式绑定dataHead
    QByteArray dataHead;
    QDataStream dataHeadStream(&dataHead,QIODevice::WriteOnly);
    dataHeadStream.setVersion(QDataStream::Qt_6_2);
    // 文件名大小+文件名+文件大小
    qint64 fileNameSize=(qint64)(fileInfo.fileName().toUtf8().size());
    dataHeadStream<<fileNameSize<<fileInfo.fileName().toUtf8()<<fileSize; // QString qint64
    // 当成功写入的时候 返回实际写入的字节数,并且触发bytesWrittern信号
    qDebug()<<"head size: "<<dataHead.size();
    qint64 dataHeadWrittenBytes=clientSock->write(dataHead);

    ui->textEdit->append("head info:");
    ui->textEdit->append("head data format: qint64+QString+qint64:");
    ui->textEdit->append(QString("fileNameSize+fileName+fileSize: %1+%2+%3").
                         arg(QString::number(fileNameSize),fileInfo.fileName(),QString::number(fileSize)));

    if (dataHeadWrittenBytes!=(qint64)dataHead.size())
    {
        ui->textEdit->append("ERROR: file head data written failed");
        file.close();
        return ;
    }

    dataHead.resize(0);



    // version 2
    // 将文件绑定到数据流上
//    QByteArray dataArray;
//    dataArray.resize(fileSize);
//    QDataStream dataStream(&dataArray,QIODevice::WriteOnly);

//    dataStream<<file.readAll();
}

void Widget::dataContinueSend()
{
    qint64 writtenNum=0;
    qint64 readNum=0;
    static qint64 dataWrittenBytes=0;
    static qint64 databytesToWirte=fileSize-dataWrittenBytes;

    if (databytesToWirte>0)
    {
        // 读取最小的放入,返回实际读取的
        readNum=file.read(dataArray.data(),qMin(databytesToWirte,sendBufferSize));

        if (readNum>0)
        {
            // 发送
            writtenNum=(clientSock->write(dataArray));

            dataWrittenBytes+=writtenNum; // 已经写了多少
            databytesToWirte-=writtenNum; // 还有多少没写

//            dataArray.clear();

            ui->progressBar->setValue(dataWrittenBytes/512);
        }

    }
    if (databytesToWirte<1024)
    {
        qDebug()<<"data";
    }

    if (dataWrittenBytes==fileSize)
    {
        file.close();
        ui->textEdit->append("DONE: client send data success...");
    }
}


void Widget::myDisconnected()
{
    clientSock->close();
}

.ui

在这里插入图片描述

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值