QT之客户端向服务器传输图片及显示

  • Post author:
  • Post category:其他




效果

在这里插入图片描述

在这里插入图片描述



设计步骤:

服务器端:

一、更改widget.ui文件,设计界面如下

在这里插入图片描述

二、打开tcpReceiver.pro添加一行代码:QT += network

在这里插入图片描述

三、widget.h文件内容

#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>
#include <QtNetwork>

namespace Ui {
class Widget;
}

class Widget : public QWidget
{
    Q_OBJECT

public:
    explicit Widget(QWidget *parent = 0);
    ~Widget();
    QTcpServer *tcpServer;
    QTcpSocket *currentClient;
    qint64 totalBytes;  //存放总大小信息
    qint64 bytesReceived;  //已收到数据的大小
    qint64 fileNameSize;  //文件名的大小信息
    QString fileName;   //存放文件名
    QFile *localFile;   //本地文件
    QByteArray inBlock;   //接收数据缓冲区
    qint64 bytesWritten;  //已经发送数据大小
    qint64 bytesToWrite;   //剩余数据大小
    qint64 loadSize;   //每次发送数据的大小
    QByteArray outBlock;  //数据缓冲区

public slots:
    void NewConnection();
    void recMessage();
    void sendMessage();
    void continueSend(qint64 numBytes);
     void disconnect();
private:
    Ui::Widget *ui;
};

#endif // WIDGET_H

四、widget.cpp文件内容

#include "widget.h"
#include "ui_widget.h"
#include <QFileDialog>
#include <QImageReader>
#include <QDebug>

Widget::Widget(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::Widget)
{
    ui->setupUi(this);
    totalBytes = 0;
    bytesReceived = 0;
    fileNameSize = 0;
    totalBytes = 0;
    bytesReceived = 0;
    fileNameSize = 0;
    tcpServer = new QTcpServer(this);
    if(!tcpServer->listen(QHostAddress::Any,6666))
    {  //**本地主机的6666端口,如果出错就输出错误信息,并关闭
        qDebug() << tcpServer->errorString();
        close();
    }
    //连接信号和相应槽函数,有新的连接进入是需处理
 connect(tcpServer,SIGNAL(newConnection()),this,SLOT(NewConnection()));
}

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

void Widget::NewConnection()
{

    //新连接进入的显示处理
    currentClient = tcpServer->nextPendingConnection();
    ui->label_2->setText(tr("%1:%2").arg(currentClient->peerAddress().toString().split("::ffff:")[1])\
            .arg(currentClient->peerPort()));
    connect(currentClient, SIGNAL(readyRead()), this, SLOT(recMessage()));
    connect(currentClient, SIGNAL(disconnected()), this, SLOT(disconnect()));

}

void Widget::recMessage()
{
    QDataStream in(currentClient);
    in.setVersion(QDataStream::Qt_5_8);
    if(bytesReceived <= sizeof(qint64)*2)
    { //如果接收到的数据小于16个字节,那么是刚开始接收数据,我们保存到//来的头文件信息

        if((currentClient->bytesAvailable() >= sizeof(qint64)*2)

                && (fileNameSize == 0))

        { //接收数据总大小信息和文件名大小信息

            in >> totalBytes >> fileNameSize;

            bytesReceived += sizeof(qint64) * 2;

        }

        if((currentClient->bytesAvailable() >= fileNameSize)

                && (fileNameSize != 0))

        {  //接收文件名,并建立文件

            in >> fileName;

            ui->label_2->setText(tr("接收文件 %1 ...").arg(fileName));

            bytesReceived += fileNameSize;
            ui->label_2->setText(fileName);
            localFile= new QFile(fileName);
            if(!localFile->open(QFile::WriteOnly))
            {
                qDebug() << "open file error!";
                return;
            }
        }
        else return;
    }
    if(bytesReceived < totalBytes)
    {  //如果接收的数据小于总数据,那么写入文件
        bytesReceived += currentClient->bytesAvailable();
        inBlock+= currentClient->readAll();
    }
    //更新进度条
    ui->progressBar->setMaximum(totalBytes);
    ui->progressBar->setValue(bytesReceived);
    if(bytesReceived == totalBytes)
    { //接收数据完成时
        //接收显示
        QBuffer buffer(&inBlock);
        buffer.open(QIODevice::ReadOnly);
        QImageReader reader(&buffer,"png");
        QImage image = reader.read();
        if(!image.isNull())
        {
            image=image.scaled(ui->label_3->size());
            ui->label_3->setPixmap(QPixmap::fromImage(image));
        }
        localFile->write(inBlock);
        localFile->close();
        inBlock.resize(0);
        //重新置0 准备下次接收
        totalBytes = 0;
        bytesReceived = 0;
        fileNameSize = 0;
        ui->label_2->setText(tr("接收文件 %1 成功!").arg(fileName));
    }
}

void Widget::disconnect()
{
    qDebug()<<"disconnect";
}


客端户:


一、更改widget.ui文件,设计界面如下

在这里插入图片描述

二、打开tcpSender.pro添加一行代码:QT += network

在这里插入图片描述

三、widget.h文件内容

#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>
#include <QtNetwork>
#include <QImageReader>


namespace Ui {
class Widget;
}

class Widget : public QWidget
{
    Q_OBJECT

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

    QTcpSocket *tcpSocket;
    QFile *localFile;  //要发送的文件
    qint64 totalBytes;  //数据总大小
    qint64 bytesWritten;  //已经发送数据大小
    qint64 bytesToWrite;   //剩余数据大小
    qint64 loadSize;   //每次发送数据的大小
    QString fileName;  //保存文件路径
    QByteArray outBlock;  //数据缓冲区,即存放每次要发送的数据
    QByteArray inBlock;   //数据缓冲区,接收
    qint64 bytesReceived;  //已收到数据的大小
    qint64 fileNameSize;  //文件名的大小信息

public slots:
    void newConnect(); //连接服务器
    void readData();  //接收数据
    void sendData();//发送数据
    void continueSend(qint64 numBytes); //继续并更新发送进度条

private slots:
    void on_pushButton_clicked();
    void on_pushButton_2_clicked();

private:
    Ui::Widget *ui;
};

#endif // WIDGET_H

四、widget.cpp文件内容


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

    tcpSocket = new QTcpSocket(this);
    loadSize = 4*1024;
    totalBytes = 0;
    bytesWritten = 0;
    bytesToWrite = 0;
    //接收
    bytesReceived = 0;
    fileNameSize = 0;
    //当有数据发送成功时,继续发送
    connect(tcpSocket,SIGNAL(bytesWritten(qint64)),this,SLOT(continueSend(qint64)));
    ui->pushButton_2->setEnabled(false);
}

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

void Widget::newConnect()
{
    //  blockSize = 0; //初始化其为0
    tcpSocket->abort(); //取消已有的连接

    //连接到主机,这里从界面获取主机地址和端口号
    tcpSocket->connectToHost(ui->lineEdit->text(), ui->lineEdit_2->text().toInt());
    ui->pushButton_2->setEnabled(true);

}


void Widget::sendData()
{
    bytesWritten = 0;
    fileName = QFileDialog::getOpenFileName(this);
    if(!fileName.isEmpty())
    {
        localFile = new QFile(fileName);
        if(!localFile->open(QFile::ReadOnly))
        {
            qDebug() << "open file error!";
            return;
        }

        //文件总大小
        totalBytes = localFile->size();
        QDataStream sendOut(&outBlock,QIODevice::WriteOnly);
        sendOut.setVersion(QDataStream::Qt_5_8);
        QString currentFileName = fileName.right(fileName.size()
                                                 - fileName.lastIndexOf('/')-1);

        //依次写入总大小信息空间,文件名大小信息空间,文件名
        sendOut << qint64(0) << qint64(0) << currentFileName;
        //这里的总大小是文件名大小等信息和实际文件大小的总和
        totalBytes += outBlock.size();
        sendOut.device()->seek(0);
        //返回outBolock的开始,用实际的大小信息代替两个qint64(0)空间
        sendOut<<totalBytes<<qint64((outBlock.size() - sizeof(qint64)*2));
        //发送完头数据后剩余数据的大小
        bytesToWrite = totalBytes - tcpSocket->write(outBlock);
        ui->label_4->setText(tr("开始发送"));
        outBlock.resize(0);
    }

}

void Widget::continueSend(qint64 numBytes)
{
    //已经发送数据的大小
    qDebug()<<"numBytes"<<numBytes;
    bytesWritten += (int)numBytes;
    if(bytesToWrite > 0) //如果已经发送了数据
    {
        //每次发送loadSize大小的数据,这里设置为4KB,如果剩余的数据不足4KB,
        //就发送剩余数据的大小
        outBlock = localFile->read(qMin(bytesToWrite,loadSize));
        //发送完一次数据后还剩余数据的大小
        bytesToWrite -= (int)tcpSocket->write(outBlock);
        //清空发送缓冲区
        outBlock.resize(0);
    } else {
        localFile->close(); //如果没有发送任何数据,则关闭文件

    }

    //更新进度条
    ui->progressBar->setMaximum(totalBytes);
    ui->progressBar->setValue(bytesWritten);
    if(bytesWritten == totalBytes) //发送完毕
    {
        ui->label_4->setText(tr("传送文件 %1 成功").arg(fileName));
        localFile->close();
    }
}


void Widget::on_pushButton_clicked()
{
    newConnect();
}

void Widget::on_pushButton_2_clicked()
{
    sendData();
}



版权声明:本文为qq_34623621原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。