我们有两个Qt应用程序。App1通过
接收器套接字监听QTcpSocket :: readDataBlock信号(在主/ GUI线程中),并将相应的时间戳打印到GUI上。
当App1和App2在同一系统上运行时,数据包完全同步。但是,当App1和App2在通过网络连接的不同系统上运行时,App2与App2中的模拟不再同步。数据包进入得更慢。更令人惊讶的是(并表明我们的实现有误),当我们停止模拟循环时,就不会再收到数据包了。这让我们感到惊讶,因为我们期望TCP协议会最终收到所有数据包。
我们基于Qt的fortune example构建了TCP逻辑。然而,幸运服务器是不同的,因为它只向每个传入客户端发送一个数据包。有人能指出我们做错了什么吗?
注意:我们使用MSVC2012(App1),MSVC2010(App2)和Qt 5.2。
QTcpServer
接受来自App2的连接,并将其存储在QTcpSocket* tcpSocket
实例中。App1以30 Hz运行模拟。对于每个模拟运行,使用以下代码(来自主/GUI线程)发送由几千字节组成的QByteArray
: QByteArray block;
/* lines omitted which write data into block */
tcpSocket->write(block, block.size());
tcpSocket->waitForBytesWritten(1);
接收器套接字监听QTcpSocket :: readDataBlock信号(在主/ GUI线程中),并将相应的时间戳打印到GUI上。
当App1和App2在同一系统上运行时,数据包完全同步。但是,当App1和App2在通过网络连接的不同系统上运行时,App2与App2中的模拟不再同步。数据包进入得更慢。更令人惊讶的是(并表明我们的实现有误),当我们停止模拟循环时,就不会再收到数据包了。这让我们感到惊讶,因为我们期望TCP协议会最终收到所有数据包。
我们基于Qt的fortune example构建了TCP逻辑。然而,幸运服务器是不同的,因为它只向每个传入客户端发送一个数据包。有人能指出我们做错了什么吗?
注意:我们使用MSVC2012(App1),MSVC2010(App2)和Qt 5.2。
编辑:所谓包,是指单个模拟实验的结果,其中包含一堆数字,写入QByteArray block
中。然而,前几位包含了QByteArray
的长度,以便客户端可以检查是否已接收到所有数据。当信号QTcpSocket::readDataBlock被触发时,将调用以下代码:
QDataStream in(tcpSocket);
in.setVersion(QDataStream::Qt_5_2);
if (blockSize == 0) {
if (tcpSocket->bytesAvailable() < (int)sizeof(quint16))
return; // cannot yet read size from data block
in >> blockSize; // read data size for data block
}
// if the whole data block is not yet received, ignore it
if (tcpSocket->bytesAvailable() < blockSize)
return;
// if we get here, the whole object is available to parse
QByteArray object;
in >> object;
blockSize = 0; // reset blockSize for handling the next package
return;
tcpSocket->bytesAvailable()
恰好有1222个字节可用,则似乎存在读取比所需更多数据的风险。从外观上看,您会同时读取下一个块的开头-因此可能需要改用in.readBytes()
,在那里您可以指定要读取的数量(并在之后验证它实际上读取了那么多数据)。但是这也取决于您的协议是如何的。例如,如果它是一个简单的请求/响应,其中您的发送方永远不会在收到前一个数据包的回复之前发送任何数据,则当前代码似乎没有问题。 - nostcpSocket->bytesAvailable()
确实大于blockSize
。 @Merlin069:这个问题并不是完全重复的,答案或多或少是相同的。但我不能将答案应用到我的情况中,因为我们使用的是无法像QByteArray
那样解析和追加的QDataStream
。我必须使用QDataStream
,因为App1和App2在不同的平台上。我尝试过从https://dev59.com/YoXca4cB1Zd3GeqPECaO中的等待循环中使用`in.device()->seek()`进行重新解析,但是由于设备不是随机访问的,所以这是不允许的。 - c_k