我需要通过 QTcpSocket
发送二进制数据。我正在考虑使用 QDataStream
,但我遇到了一个问题 - 如果在我尝试读取时没有数据到达,它会静默失败。
例如,如果我有以下代码:
QString str;
stream >> str;
如果套接字中当前没有数据,它将静默失败。有没有办法告诉它阻止?
原文由 sashoalm 发布,翻译遵循 CC BY-SA 4.0 许可协议
我需要通过 QTcpSocket
发送二进制数据。我正在考虑使用 QDataStream
,但我遇到了一个问题 - 如果在我尝试读取时没有数据到达,它会静默失败。
例如,如果我有以下代码:
QString str;
stream >> str;
如果套接字中当前没有数据,它将静默失败。有没有办法告诉它阻止?
原文由 sashoalm 发布,翻译遵循 CC BY-SA 4.0 许可协议
问题有点严重。 Socket 可以分块接收数据,因此即使您等待 waitForReadyRead
它也可能会失败,因为没有足够的数据来立即读取某个对象。
要解决此问题,您必须先发送一定大小的数据,然后再发送实际数据。发送代码:
QByteArray block;
QDataStream sendStream(&block, QIODevice::ReadWrite);
sendStream << quint16(0) << str;
sendStream.device()->seek(0);
sendStream << (quint16)(block.size() - sizeof(quint16));
tcpSocket->write(block);
在接收器上,您必须等到可用数据的大小满足要求。接收方代码看起来或多或少是这样的:
void SomeClass::slotReadClient() { // slot connected to readyRead signal of QTcpSocket
QTcpSocket *tcpSocket = (QTcpSocket*)sender();
QDataStream clientReadStream(tcpSocket);
while(true) {
if (!next_block_size) {
if (tcpSocket->bytesAvailable() < sizeof(quint16)) { // are size data available
break;
}
clientReadStream >> next_block_size;
}
if (tcpSocket->bytesAvailable() < next_block_size) {
break;
}
QString str;
clientReadStream >> str;
next_block_size = 0;
}
}
小更新,根据 文档,可以在不添加额外大小信息的情况下读取 QString,因为传递给 QDataStream 的 QString 包含大小信息。大小可以这样验证:
void SomeClass::slotReadClient() { // slot connected to readyRead signal of QTcpSocket
QTcpSocket *tcpSocket = (QTcpSocket*)sender();
while(true) {
if (tcpSocket->bytesAvailable() < 4) {
break;
}
char buffer[4]
quint32 peekedSize;
tcpSocket->peek(buffer, 4);
peekedSize = qFromBigEndian<quint32>(buffer); // default endian in QDataStream
if (peekedSize==0xffffffffu) // null string
peekedSize = 0;
peekedSize += 4;
if (tcpSocket->bytesAvailable() < peekedSize) {
break;
}
// here all required for QString data are available
QString str;
QDataStream(tcpSocket) >> str;
emit stringHasBeenRead(str);
}
}
原文由 Marek R 发布,翻译遵循 CC BY-SA 3.0 许可协议
3 回答2k 阅读✓ 已解决
4 回答4.4k 阅读✓ 已解决
2 回答3.9k 阅读✓ 已解决
2 回答3.2k 阅读✓ 已解决
1 回答3.2k 阅读✓ 已解决
1 回答2.7k 阅读✓ 已解决
3 回答3.4k 阅读
我根据@Marek 的想法重新编写了代码并创建了 2 个类 - BlockReader 和 BlockWriter:
示例用法:
块阅读器:
块写入器: