1

I have server-client Qt application, where client sends data packets to server and server reads them at a set time intervals. It happens that client sends data faster than server can read thus filling all the memory on the server side. I am using QAbstractSocket::setReadBufferSize(size) to set max read buffer size on the server side and when it fills up, socket data transferring stops, and data is buffered on client side, which is what i want, but the problem is when server's QTcpSocket's internal read buffer frees up (is not full anymore), data transfer between client and server does not resume.

I've tried to use QAbstractSocket::resume() which seems to work, but Qt5.10 documentation says:

Continues data transfer on the socket. This method should only be used after the socket has been set to pause upon notifications and a notification has been received. The only notification currently supported is QSslSocket::sslErrors(). Calling this method if the socket is not paused results in undefined behavior.

I feel like I should not use that function in this situation, but is there any other solution? How do i know if socket is paused? Why data transfer does not continue automaticaly when QTcpSocket's internal read buffer is not full anymore?

EDIT 1 :

I have downloaded Qt(5.10.0) sources and pdb's to debug this situation and I can see that QAbstractSocket::readData() internal function have line "d->socketEngine->setReadNotificationEnabled(true)" which re-enables data transfering, but QAbstractSocket::readData() gets called only when QTcpSocket internal read buffer is empty (qiodevice.cpp; QIODevicePrivate::read(); line 1176) and in My situation it is never empty, because I read it only when it has enough data for complete packet.

Shouldn't QAbstractSocket::readData() be called when read buffer is not full anymore and not when it's completely empty? Or maybe i do something wrong?

Edmundas
  • 11
  • 1
  • 6
  • 1
    What do you exactly mean by "when server QTcpSocket buffer frees up" ? and by "data transfer does not resume." ? Are you doing a read operation ? You need to post your code as well – sandwood Mar 27 '18 at 08:01
  • I meant QTcpSocket's internal read buffer is not full anymore, because i read it continuously at set intervals. QTcpSocket should fill that buffer again, but it does not. Also i made main post more comprehensible. – Edmundas Mar 27 '18 at 12:08
  • 1
    About the internal read buffer you state "because I read it only when it has enough data for complete packet." How do you know it contains a complete packet without reading it? Also note that `TCP` has no notion of packets as such -- it's byte stream oriented. It sounds as if your code makes certain assumptions about the data transfer that `TCP` doesn't guarantee. You really need to show your code. Preferably a [mcve]. – G.M. Mar 27 '18 at 13:09
  • Because communication is strictly between my server and my client, I know what data is being sent. You can send fixed size packets, or in my case I send fixed size header, which contains payload size. That data wont nix up, because TCP ensures data is in order. – Edmundas Mar 29 '18 at 09:59

1 Answers1

0

Found a Workaround!

In Qt5.10 sources i can clearly see that QTcpSpcket internal read notifications is disabled (qabstractsocket.cpp; bool QAbstractSocketPrivate::canReadNotification(); line 697) when read buffer is full and to enable read notifications you need to read all buffer to make it empty OR use QAbstractSocket::setReadBufferSize(newSize) which internally enables read notifications WHEN newSize is not 0 (unlimited) and not equal to oldSize (qabstractsocket.cpp; void QAbstractSocket::setReadBufferSize(qint64 size); line 2824). Here's a short function for that:

QTcpSocket socket;
qint64 readBufferSize; // Current max read buffer size.
bool flag = false; // flag for changing max read buffer size.
bool isReadBufferLimitReached = false;

void App::CheckReadBufferLimitReached()
{
    if (readBufferSize <= socket.bytesAvailable())
        isReadBufferLimitReached = true;
    else if (isReadBufferLimitReached)
    {
        if (flag)
        {
            readBufferSize++;
            flag = !flag;
        }
        else
        {
            readBufferSize--;
            flag = !flag;
        }
        socket.setReadBufferSize(readBufferSize);
        isReadBufferLimitReached = false;
    }
}

In the function which reads data from QTcpSocket at the set intervals, BEFORE reading data, I call this function, which checks if read buffer is full and sets isReadBufferLimitReached if true. Then I read needed amount of data from QTcpSocket and AT THE END I call that function again, which, if buffer were full before, calls QAbstractSocket::setReadBufferSize(size) to set new buffer size and enable internal read notifications. Changing read buffer size by +/-1 should be safe, because you read at least 1 byte from socket.

Edmundas
  • 11
  • 1
  • 6