2

I'm having issues with receiving a transfer.

QTcpSocket->readAll() does not read enough bytes when I'm sending to it. When I send 15k bytes, it reads only some part of it and then does nothing. What am I doing wrong?

QByteArray array;

array = socket->readAll(); //just reads some part, not fully.

Why does this happen?

4

1 回答 1

10

当您调用readAll(). 这是因为 TCP 通信发生在小数据包中(每个数据包大约有 1KB 的数据,取决于很多事情)。这些数据包构成一个流,通信线路的另一端将字节写入其中。您必须在接收端组装它们。如何组装它们必须在协议中定义。

要解决此问题,您必须在组装之前等待所有预期的数据。有时不知道需要多少数据,除非您阅读它(取决于协议)。

假设您要实现一个协议,该协议说“在换行之前的一切都是我们称之为消息的东西”。现在你想收到这样的消息。这是通过连续读取并附加到目标缓冲区(如您的QByteArray)来完成的,直到出现换行符。但是,还有另一件事:当您期望第二条消息时,它可以紧跟在 TCP 流中的第一条消息之后,因此您不仅要读取第一条消息的结尾,还要读取第二条消息的开头。请记住这一点。

当不处理信号槽连接时,您可以为这样的换行符分隔消息编写一个同步接收器,如下所示:

QByteArray array;

while(!array.contains('\n')) {
    socket->waitForReadyRead();
    array += socket->readAll();
}

int bytes = array.indexOf('\n') + 1;     // Find the end of message
QByteArray message = array.left(bytes);  // Cut the message
array = array.mid(bytes);                // Keep the data read too early

processMessage(message);

处理时QTcpSocket::readyRead(),你可以做类似的事情。

void MyClass::socketReadyRead() // connected to QTcpSocket::readyRead() signal
{
    array += socket->readAll();

    if(array.contains('\n')) {
        int bytes = array.indexOf('\n') + 1;     // Find the end of message
        QByteArray message = array.left(bytes);  // Cut the message
        array = array.mid(bytes);                // Keep the data read too early

        processMessage(message);

        socketReadyRead();                       // re-call myself to process more
    }
}

当您想读取通过一个 TCP 连接发送的所有内容(直到它被对等方关闭)时,您可以以阻塞方式等待此事件,也可以在连接到正确信号的插槽中处理数据:QTcpSocket::disconnected.

阻塞:

socket->waitForDisconnected();
QByteArray array = socket->readAll();

非阻塞(使用槽处理信号):

void MyClass::socketReadyRead() // connected to QTcpSocket::readyRead() signal
{
    array += socket->readAll();
    // Do NOT process yet!
}

void MyClass::socketDisconnected() // connected to QTcpSocket::disconnected() signal
{
    processMessage(array);
}

替代的非阻塞解决方案(基本相同):

// You don't have to connect to QTcpSocket::readyRead() signal in this case

void MyClass::socketDisconnected()
{
    processMessage(socket->readAll());
}
于 2013-01-07T02:23:31.600 回答