为什么QTcpSocket收到了错误的数据?

时间:2013-06-29 15:39:53

标签: c++ qt tcp qtcpsocket qtcpserver

我正在编写一个简单的网络应用程序。客户端发送到服务器消息服务器在QTextEdit中打印它并响应客户端。 我正在使用QTcpServer和QTcpSocket。 有一个问题我无法解决。接收数据是quint16 + QTime + QString,它作为QByteArrey发送。 我使用quint16来接收数据块的大小。并且由于某种原因,客户端发送到服务器

next block size: 16 (quint16 value)
block size: 18 

服务器获取:

next block size: 30073  (quint16 value)
block size: 18 

正如您所看到的,由于某种原因,服务器从QDataStrem获取错误的变量值,它总是30073.我不明白为什么?

void Widget::slotSendToServer()
{
    logTextEdit->append("slotSendToServer()");
    QByteArray arrBlock;
    QDataStream serverSendStream(&arrBlock, QIODevice::ReadWrite);
    QString messageStr = messageLineEdit->text();

    serverSendStream << quint16(0) << QTime::currentTime()
                     << messageStr;

    serverSendStream.device()->seek(0);
    serverSendStream << (quint16)(arrBlock.size() - sizeof(quint16));

    qDebug() << "next_block_size:"
             <<(quint16)(arrBlock.size() - sizeof(quint16)) 
             << endl
             << "full size of Byte arrey:" << arrBlock.size();

    tcpSocket->write(arrBlock);
    messageLineEdit->clear();
}



void Widget::slotReadClient()
{
    logTextEdit->append("slotReadClient()");
    QTcpSocket *tcpSocket = (QTcpSocket*)sender();
    QDataStream clientReadStream(tcpSocket);

    while(true)
    {
        if (!next_block_size)
        {
            if (tcpSocket->bytesAvailable() < sizeof(quint16))
            {
                break;
            }
            clientReadStream >> next_block_size;
        }

        if (tcpSocket->bytesAvailable() < next_block_size)
        {
            break;
        }
        QTime   time;
        QString messageTextStr;
        clientReadStream >> time >> messageTextStr;

        QString messageCompleteStr =
                time.toString() + " " + "Client has sent - " 
                                + messageTextStr;
        logTextEdit->append("Message received: ");
        logTextEdit->append(messageCompleteStr);

        next_block_size = 0;

        sendToClient(tcpSocket,
                     "Server Response: Received \"" 
                      + messageTextStr + "\"");
    }
}

2 个答案:

答案 0 :(得分:2)

每次连接套接字时,应确保变量next_block_size初始化为0.

如果您不重复使用相同的QTcpSocket对象,则可以在Widget类构造函数中执行此操作,或者如果执行此操作,则可以在连接到信号connected()的插槽中执行此操作。< / p>

答案 1 :(得分:-1)

我不知道你为什么这么复杂。 这应该有效:

void Widget::slotSendToServer()
{
    logTextEdit->append("slotSendToServer()");
    QByteArray arrBlock;
    QDataStream serverSendStream(tcpSocket);

    serverSendStream << QTime::currentTime()
                     << messageLineEdit->text();
    messageLineEdit->clear();
}

void Widget::slotReadClient()
{
    logTextEdit->append("slotReadClient()");
    QTcpSocket *tcpSocket = (QTcpSocket*)sender();
    QDataStream clientReadStream(tcpSocket);

    QTime time;
    QString message;

    clientReadStream >> time >> message;

    emit YourSignal(time, message);
}

您不必担心大小,QDataStream会跟踪它,您只需要保持与写入时相同的读取顺序,因此您的缓冲区arrBlock会浪费代码。

<小时/> 根据{{​​3}},当读取时并非所有数据都可用时,我的代码应该阻止,这只是一个缺点。对于像日期和某些字符串这样的小数据,它永远不会发生。

关于你的代码,你确实把你的阅读器搞砸了while循环,所以这里有没有这个循环的修正。

void Widget::slotReadClient()
{
    logTextEdit->append("slotReadClient()");
    QTcpSocket *tcpSocket = (QTcpSocket*)sender();
    QDataStream clientReadStream(tcpSocket);

    if (next_block_size==0) {
        // need to read data size
        if (tcpSocket->bytesAvailable() < sizeof(quint16))
            return; // wait for next signal
        // next_block_size must be type of qint16
        clientReadStream >> next_block_size;
    }
    if (tcpSocket->bytesAvailable() < next_block_size) {
        // not enought data to complete read immediately
        return;  // wait for next signal
    }
    QTime time;
    QString messageTextStr;
    clientReadStream >> time >> messageTextStr;
    QString messageCompleteStr =
                time.toString() + " " + "Client has sent - " 
                                + messageTextStr;
    logTextEdit->append("Message received: ");
    logTextEdit->append(messageCompleteStr);

    // mark that data read has been finished
    next_block_size = 0;
}