QTcpSocket receiving transfer

假如想象 提交于 2019-12-08 05:59:31

问题


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?


回答1:


Most probably the socket didn't receive all data yet when you call readAll(). This is because of TCP communication happens in small packets (each having around 1KB of data, depending on a lot of things). These packets make up a stream in which the other end of the communication line writes bytes into. You have to assemble them on the receiving side. How you assemble them has to be defined in a protocol.

To solve this issue, you have to wait for all expected data before assembling it. Sometimes it is not known how much data is expected unless you read it (depending on the protocol).

Let's say you want to implement a protocol which says "everything until a line break is something we call a message". Now you want to receive such a message. This is done by successively reading and appending to a target buffer (like your QByteArray) until there comes a line break. However, there is another thing: When you expect a second message, it can be immediately after the first one in the TCP stream, so you just read not only the end of the first message, but also the beginning of the second. Just keep this in mind.

When not dealing with signal slot connection, you can write a synchronous receiver for such newline-separated messages like this:

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);

When handling QTcpSocket::readyRead(), you can do something similar.

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
    }
}

When you want to read everything sent via one TCP connection (until it gets closed by the peer), you can wait for this event either in a blocking way or process the data in a slot connected to the proper signal: QTcpSocket::disconnected.

Blocking:

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

Non-blocking (handling signals using slots):

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);
}

Alternative non-blocking solution (essentially the same):

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

void MyClass::socketDisconnected()
{
    processMessage(socket->readAll());
}


来源:https://stackoverflow.com/questions/14189015/qtcpsocket-receiving-transfer

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!