<4>[QTCN]图片网络传输工具(服务器端)

参考

<7>[QTCN]图片网络传输工具(服务器端)
说明:图片网络传输工具(服务器端)。

亮点:图片网络传输解码。

实现

PictureTcpServer.pro

QT       += network

main.cpp

#include "picturetcpserver.h"
#include <QApplication>
#include <QFont>
int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    PictureTcpServer w;
    QFont font;
    font.setPixelSize(25);
    w.setFont(font);
    w.show();
    return a.exec();
}

picturetcpserver.h


#ifndef PICTURETCPSERVER_H
#define PICTURETCPSERVER_H

#include <QWidget>
#include <QtNetwork>
#include <QTcpSocket>
#pragma execution_character_set("utf-8")
QT_BEGIN_NAMESPACE
namespace Ui { class PictureTcpServer; }
QT_END_NAMESPACE

class PictureTcpServer : public QWidget

{
    Q_OBJECT

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


    void SaveImage(QByteArray ba);  //保存图片
    void SaveData(QByteArray ba);   //保存数据

    void DelayTime(int ms);
    void ChangeEnable(bool isEnable);
    void StartListen();             //开始监听

private slots:
    void on_btnStart_clicked();

    void on_btnClear_clicked();

    void on_btnSend_clicked();

    void AcceptConnection();        //建立连接
    void ReadMyData();              //接收数据带检验
    void ReceiveData();             //普通方式接收数据
    void DisplayError(QAbstractSocket::SocketError socketError);

    void on_rbtnPT_toggled(bool checked);

private:
    Ui::PictureTcpServer *ui;

    QTcpServer m_tcpServer;
    QTcpSocket *m_pTcpServerConnection;

    QStringList m_fileNames;
    int m_count;                    //统计存放图片的张数

    QByteArray m_message;           //存放从服务器接收到的字符串
    quint16 m_basize;               //存放文件大小信息
};

#endif // PICTURETCPSERVER_H

picturetcpserver.cpp


#include "picturetcpserver.h"
#include "ui_picturetcpserver.h"
#pragma execution_character_set("utf-8")

PictureTcpServer::PictureTcpServer(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::PictureTcpServer)
{
    ui->setupUi(this);
    ChangeEnable(false);
    this->setWindowIcon(QIcon(":/1.ico"));
    this->setWindowTitle("图片网络传输工具(服务器端)");
    m_count=0;
    m_basize=0;//初始化值0
    connect(&m_tcpServer,SIGNAL(newConnection()),this,SLOT(AcceptConnection()));
}

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

 //接收数据带检验
void PictureTcpServer::ReadMyData()
{
    this->DelayTime(ui->txtTime->text().toInt());//延时等待数据处理完
    qDebug()<<"ReadMyData()接收数据带检验";
    if(m_pTcpServerConnection==nullptr){
        qDebug()<<"m_pTcpServerConnection==nullptr";
        return;
    }
    QDataStream in(m_pTcpServerConnection);
    in.setVersion(QDataStream::Qt_4_7);
    if (m_basize==0)
    {
        //判断接收的数据是否有两字节(文件大小信息)
        //如果有则保存到basize变量中,没有则返回,继续接收数据
        if (m_pTcpServerConnection->bytesAvailable()<(int)sizeof(quint16))
        {
            return;
        }
        in>>m_basize;
    }

    //如果没有得到全部数据,则返回继续接收数据
    if (m_pTcpServerConnection->bytesAvailable()<m_basize)
    {
        return;
    }

    /*将只读取剩余的数据部分,而不包括文件大小信息;
     *因为QDataStream类会按照先进先出(FIFO)的顺序读取数据流中的数据。
     *当调用in >> m_basize语句时,它会从数据流中读取指定类型和大小的数据,
     *并将其存储在变量m_basize中。而in >> m_message会继续从数据流中读取剩余的数据*/
    in>>m_message;                      //将接收到的数据存放到变量中

    ui->txtData->append(m_message);
    if (ui->ckbox->isChecked())
    {
        this->SaveData(m_message);
    }
    this->SaveImage(m_message);
    m_count+=1;
    qDebug()<<"m_count = "<<m_count;
    ui->labCount->setText(QString("提示:数据大小(%1) 图片张数(%2)").arg(QString::number(m_basize),QString::number(m_count)));
    m_basize=0;                         //重新归位0
    m_message.clear();                  //清空后重新存储

}

//保存图片
void PictureTcpServer::SaveImage(QByteArray ba)
{
    QString timeNow=QDateTime::currentDateTime().toString("yyyyMMddHHmmss");
    QString saveFileName=QCoreApplication::applicationDirPath()+tr("/imageto/%1.jpg").arg(timeNow);

    QDir folder(QCoreApplication::applicationDirPath());
    if (!folder.exists("imageto")) // 检查文件夹是否存在
    {
        if (!folder.mkpath("imageto")) // 创建文件夹并检查是否成功
        {
            // 创建文件夹失败,进行适当的错误处理
            return;
        }
    }

    QByteArray rdc=qUncompress(QByteArray::fromBase64(ba));         // 解压缩,得到解压后的二进制数据
    QImage img;
    img.loadFromData(rdc);                  // 从字节数组加载图像数据
    img.save(saveFileName);
}

//保存数据
void PictureTcpServer::SaveData(QByteArray ba)
{
    QString timeNow=QDateTime::currentDateTime().toString("yyyyMMddHHmmss");
    QString saveFileName=QCoreApplication::applicationDirPath()+tr("/imagedata/%1.txt").arg(timeNow);

    QDir folder(QCoreApplication::applicationDirPath());
    if (!folder.exists("imagedata")) // 检查文件夹是否存在
    {
        if (!folder.mkpath("imagedata")) // 创建文件夹并检查是否成功
        {
            // 创建文件夹失败,进行适当的错误处理
            return;
        }
    }

    QString str(ba);
    QFile file(saveFileName);
    if (file.open(QFile::WriteOnly| QIODevice::Truncate))
    {
        file.write(str.toLatin1());
        file.close();
    }
}

//延时等待功能
void PictureTcpServer::DelayTime(int ms)
{
    QTime t=QTime::currentTime().addMSecs(ms);//当前时间的基础上增加ms毫秒,得到一个目标时间点t
    while(QTime::currentTime()<t)
    {/*处理当前线程的事件队列,并等待最多100毫秒来接收新的事件。
      *处理所有类型的事件,包括定时器事件、绘图事件等
      *通过不断处理事件,可以确保程序在等待期间仍然能够响应其他事件,以避免程序无响应或阻塞*/
        QCoreApplication::processEvents(QEventLoop::AllEvents,100);
    }
}

void PictureTcpServer::ChangeEnable(bool isEnable)
{
    ui->btnStart->setEnabled(!isEnable);
    ui->btnSend->setEnabled(isEnable);
}

//开始监听
void PictureTcpServer::StartListen()
{
    if (!m_tcpServer.listen(QHostAddress::Any,ui->txtPort->text().toInt()))
    {
        ui->labCount->setText(tr("提示:发生错误(%1)").arg(m_tcpServer.errorString()));
        m_tcpServer.close();        //关闭TCP服务器,停止接受新的连接请求
        return;
    }
    ui->btnStart->setEnabled(false);
    ui->btnSend->setEnabled(false);
    ui->labCount->setText(tr("提示:正在监听"));
}

//建立连接
void PictureTcpServer::AcceptConnection()
{
    // 获取TCP服务器对象的下一个待处理的连接
    m_pTcpServerConnection=m_tcpServer.nextPendingConnection();
    connect(m_pTcpServerConnection,&QTcpSocket::readyRead,this,[=](){
        if (ui->rbtnPT->isChecked())    //普通方式接收数据
        {
            ReceiveData();
        }
        else                            //数据检验方式接收数据
        {
            ReadMyData();
        }
    });


    connect(m_pTcpServerConnection,SIGNAL(error(QAbstractSocket::SocketError)),this,SLOT(DisplayError(QAbstractSocket::SocketError)));

    connect(m_pTcpServerConnection,&QTcpSocket::disconnected,this,[=](){
        /*为了避免内存泄漏,调用deleteLater()函数以删除不再需要的QAbstractSocket对象;*/
        m_pTcpServerConnection->deleteLater();
        /*deleteLater()函数的作用是在事件循环处理完当前事件后删除对象,这样可以避免直接在槽函数中删除对象导致的问题,
         *而不会立即删除它。*/
    });

    m_tcpServer.close();            //关闭TCP服务器,停止接受新的连接请求
    ui->labCount->setText(tr("提示:客户端连接成功"));
    ui->btnSend->setEnabled(true);
}

//普通方式接收数据
void PictureTcpServer::ReceiveData()
{
    //this->DelayTime(ui->txtTime->text().toInt());
    QByteArray read=m_pTcpServerConnection->readAll();

    if (!read.isEmpty())
    {
        ui->txtData->append(QString::fromUtf8(read));
        if (ui->ckbox->isChecked())
        {
            this->SaveData(read);
        }
    }
}

void PictureTcpServer::DisplayError(QAbstractSocket::SocketError socketError)
{
    /* 调用close()函数后,QAbstractSocket对象进入QAbstractSocket::UnconnectedState状态,
     * 表示与客户端的连接已经断开,此时对象将无法进行进一步的通信或更新*/
    m_pTcpServerConnection->close();
    ui->labCount->setText(QString("提示:断开连接,错误(%1)").arg(m_pTcpServerConnection->errorString()));
    this->ChangeEnable(false);
}



void PictureTcpServer::on_btnStart_clicked()
{
    this->StartListen();
}


void PictureTcpServer::on_btnClear_clicked()
{
    ui->txtData->clear();
}


void PictureTcpServer::on_btnSend_clicked()
{
    m_pTcpServerConnection->write(ui->txt1->toPlainText().toUtf8());
    if (m_pTcpServerConnection->flush())
    {
        ui->labCount->setText(tr("提示:发送数据成功"));
    }
}


void PictureTcpServer::on_rbtnPT_toggled(bool checked)
{
    qDebug()<<"接收方式普通方式 使用="<<checked;
    if(checked)
    {
        if(m_pTcpServerConnection==nullptr)
            return;
        m_pTcpServerConnection->readAll(); // 读取并丢弃缓冲区中的数据

        qWarning() << "缓冲区已清空";

    }
}


picturetcpserver.ui

在这里插入图片描述

效果

List item

源码

Gitee:05PictureTcpServer[QTCN]图片网络传输工具(服务器端)

模糊知识点

  1. QDataStream类会按照先进先出(FIFO)的顺序读取数据流中的数据
  • 当调用in >> m_basize语句时,它会从数据流中读取指定类型和大小的数据,并将其存储在变量m_basize中。
  • 而in >> m_message会继续从数据流中读取剩余的数据
  1. QTcpServer::close() 关闭TCP服务器,停止接受新的连接请求

  2. QTcpSocket::close() QAbstractSocket对象进入QAbstractSocket::UnconnectedState状态,表示与客户端的连接已经断开,此时对象将 无法 进行进一步的通信或 更新

  3. QTcpSocket::bytesAvailable()函数用于判断是否有足够的字节可供读取,不足则可以继续等待更多数据

//调用bytesAvailable()函数来检查是否已经接收到了完整的数据。
//如果可读取的字节数小于文件大小(m_basize),则返回并继续等待更多数据
if (m_pTcpServerConnection->bytesAvailable()<m_basize)
	return;

通过这个例子可见,当时自己开发的Qt广告机客户端(下位机)QTcpSocket::eadyRead()处理的局限

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值