<4>[QTCN] Picture network transmission tool (server side)

reference

<7>[QTCN] picture network transmission tool (server side)
description: picture network transmission tool (server side).

Highlights: picture network transmission decoding.

accomplish

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

insert image description here

Effect

List item

source code

Gitee: 05PictureTcpServer[QTCN] picture network transmission tool (server side)

fuzzy knowledge points

  1. QDataStreamThe class will FIFOread the data in the data stream in the order of first in first out ( )
  • When the in >> m_basize statement is called, it reads data of the specified type and size from the data stream and stores it in the variable m_basize.
  • And in >> m_message will continue to read the remaining data from the data stream
  1. QTcpServer::close()Close the TCP server and stop accepting new connection requests

  2. QTcpSocket::close()The QAbstractSocket object enters the QAbstractSocket::UnconnectedState state, indicating that the connection with the client has been disconnected. At this time, the object will 无法conduct further communication or更新

  3. QTcpSocket::bytesAvailable()The function is used to judge whether 足够there are bytes available for reading, if not enough, you can continue to wait for more data

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

Through this example, we can see that the Qt advertising machine client (lower computer) developed by ourselves at that time QTcpSocket::eadyRead()was limited in processing

Guess you like

Origin blog.csdn.net/qq_47355554/article/details/131756229
Recommended