PDA

View Full Version : QTcpSocket reading stucks



mentalmushroom
17th February 2011, 13:26
Hi there! I am coding NNTP client application. It is convenient to read data line-by-line in blocking mode, so I do it in the next way:



QString s;
while (s != ".")
{
socket.waitForReadyRead();
QByteArray b = socket.readLine();

s = QString(b);
}


The problem is the app at some point begins reading lines slow and after some time stops reading at all. However, the following code works fine:



QByteArray b;
while (!b.endsWith("\r\n.\r\n"))
{
QByteArray portion;
portion = socket.readAll();
b.append(portion);
}


What can be the issue and is there any solution for it?

wysota
17th February 2011, 22:46
You are reading one line yet more than one line could be already waiting in the socket. Eventually you're lagging so much that the receive buffer fills completely and the socket doesn't receive any more data waiting for you to read what's already there.

mentalmushroom
18th February 2011, 08:46
thank you!

mentalmushroom
18th February 2011, 12:56
Just noticed that reading large amounts of data via QTextStream gets stuck while reading via QTcpSocket works fine.

The sample code works without any problems:


QString s;
while (s != ".")
{
if (!socket.canReadLine())
socket.waitForReadyRead();

// using socket readLine method
s = QString(socket.readLine()).simplified();
}


The following sample works slow and eventually hangs up:


QTextStream ts(&socket);
QString s;
while (s != ".")
{
if (!socket.canReadLine())
socket.waitForReadyRead();

// using QTextStream readLine method
s = ts.readLine();
}

wysota
18th February 2011, 13:40
I suggest you change your code to non-blocking approach, then it's much easier:

QTextStream ts(&socket); // declared elsewhere
void Sth::onReadyRead(){
while(socket.canReadLine()){
s = ts.readLine();
}
}
If you insist on having it blocking:

bool stop = false;
while(!stop) {
while(!stop && socket.canReadLine()) {
s = ts.readLine();
if(s.trimmed()==".") stop = true;
}
if(!stop) socket.waitForReadyRead(5000);
}
Your code is faulty bvecause you assume that after waitForReadyRead() there will be a complete line in the socket.

mentalmushroom
18th February 2011, 14:40
Yes, I understand, but due to short lines practically it always receives the whole line after that signal (my first sample never gets stuck although I wait for readyRead signal only once).

Your code doesn't work either, but if I simply change
s = ts.readLine() to
s = QString(socket.readLine()) everything works like a charm.

wysota
18th February 2011, 14:47
The two lines of code are not equivalent!


due to short lines practically it always receives the whole line after that signal
So your program will "practically work" instead of just working. If the line is at least two bytes long (and if it not empty then it always is) then due to network congestion (which is out of your control) it can be fragmented into more than one tcp segment and your code will start returning empty lines or worse.

mentalmushroom
18th February 2011, 14:50
The two lines of code are not equivalent!so what is wrong with the first line?

So your program will "practically work" instead of just working....yes, yes... i already changed that, just wanted to say there is another issue

wysota
18th February 2011, 14:58
so what is wrong with the first line?
It may be using a different encoding than QTextStream. There is no point in using QTextStream to read line-by-line if you want the same behaviour as when reading directly from the socket.

mentalmushroom
18th February 2011, 15:06
Thanks again. I thought QTextStream is right for that purpose - reading text from different devices and it automatically removes \r\n from the line end

wysota
18th February 2011, 15:25
QTextStream is for reading text token by token (word by word). If you use readLine() it behaves in the same way as QIODevice::readLine() only that it uses a given text codec on the data being read.