c++ - 调用 QDataStream::writeRawData 后 QDataStream 为空

标签 c++ qt c++11 qdatastream

我有一个相当奇怪的问题,使用 QDataStream,或者至少对我来说很奇怪,因为我根本不理解这种行为。

当然,我的问题来自一个大项目,但我设法用一个最小的例子重现了这种奇怪的行为,我现在将对此进行描述。

我有两个类(class)

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

Reader 通过 QTcpSocket 读取数据,将每个接收到的数据 block 打包到 QByteArray 中,并通过 Qt 信号将该数组发送到 解析器

解析器将所有接收到的数据 block 写入它自己的QDataStream,然后解析来自该流的数据包。

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

为什么? QDataStream::writeRawData 声称已写入的数据在哪里?

您可以在这篇文章的 和 找到代码。

环境:Windows 7 Enterprise SP1 64 位上的 Qt 5.9.1(MSVC 2015,32/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);
    }
}

解析器.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

解析器.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 是的,我将我的最小示例项目称为“删除”:'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() 检索用于包装您的 QByteArrayQBuffer 并重置该对象的位置。

mStream.device()->reset()

关于c++ - 调用 QDataStream::writeRawData 后 QDataStream 为空,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55146979/

相关文章:

c++ - 用于集群的 C/C++ 机器学习库

c++ - QGraphicsView fitInView 边距

c++ - qt | QPixmap 缩放不正确

c++ - 未调用 std::function 移动构造函数

c++ - 模板别名难度

c++ - 为什么不总是包含所有标准标题?

c++ - SFML VertexArray 不是 sf 的成员

c++ - 使用 OpenCV 的目标检测项目

c++ - 插槽在 QT 应用程序中未接收到信号

c++ - 为什么我们可以使用 SFINAE 检测 operator() 的默认参数值的存在,但不能检测自由函数和 PMF 的默认参数值?