从QLocalSocket中读取超过2048个字节时出现问题。这是我的服务器端代码:
clientConnection->flush(); // <-- clientConnection is a QLocalSocket
QByteArray block;
QDataStream out(&block, QIODevice::WriteOnly);
out.setVersion(QDataStream::Qt_5_0);
out << (quint16)message.size() << message; // <--- message is a QString
qint64 c = clientConnection->write(block);
clientConnection->waitForBytesWritten();
if(c == -1)
qDebug() << "ERROR:" << clientConnection->errorString();
clientConnection->flush();下面是我在客户端中读取数据的方式:
QDataStream in(sock); // <--- sock is a QLocalSocket
in.setVersion(QDataStream::Qt_5_0);
while(sock->bytesAvailable() < (int)sizeof(quint16)){
sock->waitForReadyRead();
}
in >> bytes_to_read; // <--- quint16
while(sock->bytesAvailable() < (int)bytes_to_read){
sock->waitForReadyRead();
}
in >> received_message;客户端代码连接到readyRead信号,并在第一次调用插槽后断开。
为什么我只能读取2048字节?
==EDIT==
在peppe回复之后,我更新了我的代码。下面是它现在的样子:
服务器端代码:
clientConnection->flush();
QByteArray block;
QDataStream out(&block, QIODevice::WriteOnly);
out.setVersion(QDataStream::Qt_5_0);
out << (quint16)0;
out << message;
out.device()->seek(0);
out << (quint16)(block.size() - sizeof(quint16));
qDebug() << "Bytes client should read" << (quint16)(block.size() - sizeof(quint16));
qint64 c = clientConnection->write(block);
clientConnection->waitForBytesWritten();客户端代码:
QDataStream in(sock);
in.setVersion(QDataStream::Qt_5_0);
while(sock->bytesAvailable() < sizeof(quint16)){
sock->waitForReadyRead();
}
quint16 btr;
in >> btr;
qDebug() << "Need to read" << btr << "and we have" << sock->bytesAvailable() << "in sock";
while(sock->bytesAvailable() < btr){
sock->waitForReadyRead();
}
in >> received_message;
qDebug() << received_message;我仍然无法读取更多的数据。
发布于 2013-02-12 23:33:16
out.setVersion(QDataStream::Qt_5_0);
out << (quint16)message.size() << message; // <--- message is a QString这是错误的。"message“的序列化长度将是message.size() *2+4个字节,因为QString将自己的长度预置为一个quint32,而每个QString字符实际上是一个UTF16代码单元,因此它需要2个字节。期望在读取器中只读取message.size()字节将导致QDataStream短时间读取,这是未定义的行为。
请务必检查这些行后面的“块”的大小--它将是2+4+2* message.size()字节。所以你需要修正这个数学模型。您可以放心地假设它不会改变,因为Qt数据类型is known and documented的序列化格式。
不过,我确实认识到了前缀长度的“设计模式”。它可能来自Qt附带的财富网络示例。UTF 16代码单元的字符串长度(这是没有意义的,因为它不是如何序列化的) --它预先考虑了序列化后的QString的长度。看看它做了什么:
out << (quint16)0;
out << fortunes.at(qrand() % fortunes.size());
out.device()->seek(0);
out << (quint16)(block.size() - sizeof(quint16));首先,它通过编写0在输出中保留一些空间。然后序列化一个QString。然后,它使用序列化的QString的长度回溯并覆盖0 --此时,它正好是block.size()减去表示长度的前面的整数(我们知道quint16的序列化长度是sizeof(quint16))
重复一遍,实际上有两个原因解释了为什么这个例子是这样编写的,而且它们之间有某种联系:
operator>>反序列化对象时,它成功解码对象所需的所有数据都必须可用。因此,在确保所有数据都已收到之前,您不能使用它。这将我们带到:1+2意味着您必须使用某种其他机制来了解(在接收方)您是否已经拥有所需的所有数据,或者您必须等待更多数据。例如,你可以引入带内标记,比如\r\n (就像IRC或者--在某种程度上-- HTTP do)。
fortune示例中的解决方案是在“实际”数据(带有fortune消息的序列化QString )前面加上该数据的字节长度;然后发送该长度(作为16位整数),后跟数据本身。
接收器首先读取长度;然后它读取那么多字节,然后它知道它可以解码命运。如果没有足够的数据可用(无论是长度还是有效载荷本身),客户端什么都不做,等待更多数据。
请注意:
https://stackoverflow.com/questions/14831819
复制相似问题