QdataStream在QDATASTREAM :: WRITERAWDATA的呼叫后空

QDataStream empty after call of QDataStream::writeRawData

本文关键字:呼叫 WRITERAWDATA QDATASTREAM QdataStream      更新时间:2023-10-16

我有一个相当奇怪的问题,使用QDataStream,或者至少对我来说很奇怪,因为我完全不了解行为。

当然,我的问题来自一个大项目,但是我设法以最小的例子来复制这种奇怪的行为,我将现在描述。

我有两个类

  1. 二进制数据读取器Reader
  2. 二进制数据解析器Parser

Reader通过QTcpSocket读取数据,将每个收到的数据块打包到QByteArray中,并通过QT信号发送该数组到Parser

Parser将所有收到的数据块写入其自己的QDataStream,然后从该流中解析数据包。

出现问题时,当Parser将收到的QByteArray数据写入其QDataStream时。QDataStream::writeRawData的返回值正确返回了书面字节的数量,但是QDataStream::atEnd返回trueQDataStream::device.bytesAvailable返回零。

为什么?数据QDataStream::writeRawData在哪里宣称写了?

您可以在此帖子中找到代码。

环境: QT 5.9.1(MSVC 2015,32/64位)Windows 7 Enterprise SP1 64位


Reader.h

#ifndef READER_H
#define READER_H
#include <QAbstractSocket>
#include <QByteArray>
#include <QDataStream>
#include <QHostAddress>
#include <QObject>
class Reader : public QObject
{
    Q_OBJECT
public:
    Reader(const QHostAddress ip, quint16 port);
    virtual ~Reader();
signals:
    void signalNewData(const QByteArray data);
private slots:
    void slotOnReadyRead();
private:
    QAbstractSocket *mSocket;
    QDataStream mStream;
};
#endif // READER_H

reader.cpp

#include "reader.h"
#include <QTcpSocket>
Reader::Reader(const QHostAddress ip, quint16 port)
    : mSocket(new QTcpSocket(this))
    , mStream()
{
    mStream.setDevice(mSocket);
    mStream.setVersion(QDataStream::Qt_5_9);
    mStream.setByteOrder(QDataStream::LittleEndian);
    connect(mSocket, &QIODevice::readyRead, this, &Reader::slotOnReadyRead);
    mSocket->connectToHost(ip, port, QIODevice::ReadOnly);
}
Reader::~Reader()
{
    mSocket->disconnectFromHost();
    delete mSocket;
    mSocket = nullptr;
}
void Reader::slotOnReadyRead()
{
    mStream.startTransaction();
    quint64 availableBytesForReading = mStream.device()->bytesAvailable();
    QByteArray binaryDataBlock;
    char *tmp = new char[availableBytesForReading];
    mStream.readRawData(tmp, availableBytesForReading);
    binaryDataBlock.append(tmp, availableBytesForReading);
    delete[] tmp;
    tmp = nullptr;
    if (mStream.commitTransaction())
    {
        emit signalNewData(binaryDataBlock);
    }
}

parser.h

#ifndef PARSER_H
#define PARSER_H
#include <QByteArray>
#include <QDataStream>
#include <QObject>
class Parser : public QObject
{
    Q_OBJECT
public:
    Parser();
public slots:
    void slotOnNewData(const QByteArray data);
private:
    QDataStream mStream;
};
#endif // PARSER_H

parser.cpp

#include "parser.h"
#include <QDebug>
Parser::Parser()
    : mStream(new QByteArray(), QIODevice::ReadWrite)
{
    mStream.setVersion(QDataStream::Qt_5_9);
    mStream.setByteOrder(QDataStream::LittleEndian);
}
void Parser::slotOnNewData(const QByteArray data)
{
    const char *tmp = data.constData();
    int numberOfBytesWritten = mStream.writeRawData(tmp, data.length());
    qDebug() << "numberOfBytesWritten:" << numberOfBytesWritten << endl;
    qDebug() << "QDataStream::status():" << mStream.status() << endl;
    qDebug() << "QDataStream::atEnd():" << mStream.atEnd() << endl;
    qDebug() << "QDataStream::device.bytesAvailable():" << mStream.device()->bytesAvailable() << endl;
}

main.cpp

#include <QCoreApplication>
#include "reader.h"
#include "parser.h"
int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);
    Reader *reader = new Reader(QHostAddress("<insert IP>"), <insertPort>);
    Parser *parser = new Parser();
    QObject::connect(&a, &QCoreApplication::aboutToQuit, reader, &QObject::deleteLater);
    QObject::connect(&a, &QCoreApplication::aboutToQuit, parser, &QObject::deleteLater);
    QObject::connect(reader, &Reader::signalNewData, parser, &Parser::slotOnNewData);
    return a.exec();
}

delete.pro 是的,我称我的最小示例项目'delete':'d

QT += core network
QT -= gui
CONFIG += c++11
TARGET = delete
CONFIG += console
CONFIG -= app_bundle
TEMPLATE = app
SOURCES += main.cpp 
    reader.cpp 
    parser.cpp
# The following define makes your compiler emit warnings if you use
# any feature of Qt which as been marked deprecated (the exact warnings
# depend on your compiler). Please consult the documentation of the
# deprecated API in order to know how to port your code away from it.
DEFINES += QT_DEPRECATED_WARNINGS
# You can also make your code fail to compile if you use deprecated APIs.
# In order to do so, uncomment the following line.
# You can also select to disable deprecated APIs only up to a certain version of Qt.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000    # disables all the APIs deprecated before Qt 6.0.0
HEADERS += 
    reader.h 
    parser.h

问题不是没有数据,而是您当前的位置在数据末尾。使用device()检索用来包装QByteArray并重置该对象的位置的QBuffer

mStream.device()->reset()