【问题标题】:QDataStream writing wrong values to QByteArrayQDataStream 将错误的值写入 QByteArray
【发布时间】:2019-05-26 18:17:50
【问题描述】:

我正在 Qt 中编写一个简单的基于 TCP 的网络应用程序,并希望使用 QDataStreamQByteArray 通过网络发送数据。问题是当我将数据放入QByteArray 时,它们被“归零”。例如(MainWindow 中连接定时器超时信号的槽):

void MainWindow::SendPlayer1Data(){
  QByteArray block;
  QDataStream s(&block, QIODevice::OpenModeFlag::ReadWrite);
  QString h="hello";
  s<<h;
  qDebug() << "h:        " << data;
  qDebug() << "block:    " << QString(block); // equivalent to s >> h on receiving end
  qDebug() << "block[0]: " << int(block[0]);
}

h:         "hello"
block:     ""
block[0]:  0

我一开始收到"hello",但之后我只收到""qint32 也是如此。客户端和服务器都显示 QByteArray 大小为 14 字节,因此 QDataStream 将数据写入该数组,但它使它们成为 0(当我使用 s &gt;&gt; h 然后使用 qDebug() &lt;&lt; h 时,它显示 ""

【问题讨论】:

    标签: c++ qt qbytearray qdatastream


    【解决方案1】:

    好的,我想通了。 问题不在于QByteArray 或套接字,因为正如@William Miller 所提到的,数据就在那里。 问题在于客户端的QDataStream - 我决定每次调用负责接收数据的插槽时都创建一个新的QDataStream 对象。这样我就可以轻松地将数据打包到QByteArray,每次都发送和接收。 接收的客户端函数:

    void ClientTcpHelper::ReceivePacket(){
    
    if(socket.waitForReadyRead(20)){
    
        //qDebug()<<"Packet: "<<socket.peek(30)<<endl;
        qDebug()<<"Receiving packet!"<<endl;
    
        Data=socket.readAll();
        emit DataReceived();
    
    
    }
    else{
        //qDebug()<<"Failed to receive packet!"<<endl;
    
    }}
    

    并将数据解包到变量中:

    void ClientTcpHelper::UnpackData(){
    
    stream=new QDataStream (&this->Data,QIODevice::OpenModeFlag::ReadWrite);
    *stream>>h>>a>>b;
    Data.clear();
    delete stream;}
    

    h,a 和 b 是类的成员。

    不幸的是,我无法解释为什么每次都需要在这里销毁QDataStream,以便从一开始就按照我的意愿处理数据。

    【讨论】:

      【解决方案2】:

      这里的问题是将QString 直接写入需要QByteArray 的流,请考虑以下事项

      QByteArray block;
      QDataStream s(&block, QIODevice::OpenModeFlag::ReadWrite);
      QString h = "hello";
      s << h;
      qDebug() << block;
      

      哪些输出

      "\x00\x00\x00\n\x00h\x00""e\x00l\x00l\x00o"
      

      所以数据是存在的,它只是不存在人们可能期望的那样。解决此问题的最简单方法是从使用 UTF8(或您选择的其他编码)编码的字符串创建 QByteArray。这可以轻松完成,

      QByteArray block;
      QDataStream s(&block, QIODevice::OpenModeFlag::ReadWrite);
      QString h = "hello";
      QByteArray data(h.toUtf8(), 5);
      s << data;
      qDebug() << block;
      

      哪些输出

      "\x00\x00\x00\x05hello"
      

      因为当这个 QByteArray 通过 QDataStream 发送时,数组的长度和 3 个 NULL 字符被前置 - 如果缓冲区大于相对较小的 5,则存在 NULL 字符(您可以通过传递一个更大的值来自己测试 - 256 的小因子最能说明问题 - 作为 QByteArray 构造函数中的第二个参数,因为这是缓冲区长度)。但是,如果您尝试从 NULL-commenced QByteArray 显式构造 QString(如 s &gt;&gt; h 所做的那样),它将创建一个空字符串。要更正此问题,您可以使用 QByteArray::remove() 像这样删除第一个 4 字节

      QByteArray block;
      QDataStream s(&block, QIODevice::OpenModeFlag::ReadWrite);
      QString h = "hello";
      QByteArray data(h.toUtf8());
      s << data;
      qDebug() << QString::fromUtf8(block.remove(0, 4));
      

      哪些输出

      "hello"
      

      完整示例

      #include <qbytearray.h>
      #include <qdatastream.h>
      #include <qdebug.h>
      
      int main() {
        QByteArray block;
        QDataStream s(&block, QIODevice::OpenModeFlag::ReadWrite);
        QString h = "hello";
        QByteArray data(h.toUtf8());
        s << data;
        qDebug() << QString::fromUtf8(block.remove(0, 4));
      }
      

      【讨论】:

      • 非常感谢您提供的解决方案,它可以完成工作。但是,如果我必须手动删除 NULL 字节,它不会使使用 QDataStream 毫无意义吗?我不应该直接写QByteArray来写我想要的吗?
      • @Kestrel QDataStream 的重点是序列化数据,但是在串行上写入QByteArray 需要发送一个长度 - 考虑到您可以发送未被NULL 终止的数据,如果没有缓冲区的长度,您将获得未定义的行为。可以使用QDataStream::writeRawData() 一次发送一个字节而无需任何帧,但我无法让它工作,所以我将它排除在我的答案之外。
      猜你喜欢
      • 2014-06-09
      • 2020-07-10
      • 1970-01-01
      • 2020-08-15
      • 1970-01-01
      • 2023-03-08
      • 1970-01-01
      • 1970-01-01
      • 2020-12-08
      相关资源
      最近更新 更多