[Qt-interest] Why Bus error clientSocket->waitForConnected()?

Thiago Macieira thiago at kde.org
Mon May 3 15:46:08 CEST 2010


Em Segunda-feira 03 Maio 2010, às 10:17:19, Kustaa Nyholm escreveu:
> > No, that was a good design. All of the API is non-blocking and that's a
> > good design.
> 
> Why? Who needs a non blocking readline? Like I've already said several
> times I would love to see a use case where this is needed...

Because none of the QIODevice API is blocking, except for the waitFor 
functions.

The design principle is that you can call any function and expect it to return 
immediately. That makes the API usable from an event-driven application in the 
GUI thread, without worrying that the GUI might freeze because the socket 
hasn't received enough bytes.

> >> or a bad decision to call it readline when many other APIs/libraries and
> >> common user expectation is that readline will block.
> > 
> > Maybe the bad decision was to return anything if full a line can't be
> > read but the device isn't at the end yet.
> 
> So you are conceding that it should block  or that it was a bad piece of
> API desing......  ;-)

No, I am not conceding that it should block.

I said "the bad decision was to return anything if a full line can't be read". 
That means it shouldn't return anything at all, indicating that no lines can 
be read yet.

You have to wait for more data to be available before you can read.

> > Unfortunately, by the time we made QIODevice properly understand "can't
> > read because it's EOF" and "can't read because there is no more data but
> > the socket/process can still receive more", the readLine behaviour was
> > set.
> 
> So it was not a perfect design decision?

No. Backwards compatibility dictated that we kept the existing behaviour.

But to tell you the truth, I hadn't thought of this case. I simply expected 
everyone to use canReadLine.

> > Sometimes devices and files end without a newline. So readLine() returns
> > an unfinished line if EOF is found first.
> 
> As most people would expect, I guess.
> 
> However,the documentation for QSocket::readLine says:
> 
>  Returns "" if canReadLine() returns FALSE.

No, it doesn't. See http://doc.qt.nokia.com/4.6/qiodevice.html#readLine

Please stop reading Qt 3.3 documentation. It's irrelevant.

However, Qt 3.3 had the behaviour I wanted it to have in Qt 4. It was changed 
in the 4.0 process and now we have to live with it.

> So it does not return the last line at all if it is not new line
> terminated?

It does in Qt 4.

> > As I said before, if you want to block, you have to call a "waitFor"
> > function. There's none above, so it doesn't block. it simply busy-loops
> > forever.
> 
> You insist on telling me how to use API, I don't need that information, I
> know how to use it. My sole point was that the API design could have been
> better, alas too late to fix that now.

The API design is perfectly good. The API is non-blocking and that was 
intentional.

> >> So I think Qt has got this small detail wrong.
> > 
> > Or you did.
> 
> That is totally possible, but obviously I do not agree, but you don't get
> Qt folks to admit an error often, even the tiniest...

The hundreds of bugs fixed and suggestions implemented indicate that we admit 
we made mistakes and we fix them.

The deprecating of APIs and replacing with better ones are also examples of 
that (see QWeakPointer replacing QPointer, QNetworkAccessManager replacing 
QHttp, the Qt Animation Framework replacing QTimeline, QElapsedTimer replacing 
QTime for interval calculations, etc.)

> > canReadLine() will return true for as long as there's a line to be read.
> > If the device, process or socket is closed without a newline at the end,
> > canReadLine() will return false for that last chunk of data. But
> > readLine() will return it.
> 
> According to the documentation this is not so, but regardless, how
> is this API proposed to be used?
> 
> With Java API design I would do something like:
> 
>         while (null != (line = reader.readLine()))
>             processLine( line );

If the device is a file or all data is available (such as a closed socket, 
finished process or finished QNetworkReply):
    QByteArray line;
    while (!(line  = device.readLine()).isNull())
        processLine(line);

If the device is still receiving data, in your slot connected to readyRead():

void MyClass::slotReadyRead()
{
    while (device.canReadLine())
        processLine(device.readLine());
}

void MyClass::slotDisconnected() /* or slotFinished */
{
    if (device.bytesAvailable())
        processLine(device.readLine()); /* device finished without a newline */
}

Or if you insist in doing it the blocking way:

    while (device.waitForReadyRead(-1)) {
        while (device.canReadLine())
            processLine(device.readLine());
    }
    if (device.bytesAvailable())
        processLine(device.readLine()); /* device finished without a newline */

> How about Qt? I've not compiled nor tested following, so I'm working
> from the documentation acting as a novice:
> 
> First I have several issues with the waitForMore documentation, which
> says:

Please stop reading Qt 3.3 documentation. It's waitForReadyRead in Qt 4.

>     If msecs is -1 the call will block indefinitely.
> 
> I presume this means block until data is available, but what about
> if there is an error? What about if there is eof / socket closed?
> 
>     The documentation says: "...no error occurred (i.e. it does not return
>    -1)"
> 
> so I presume that in case of error waitForMore will return with -1.
> 
> Ok, but is eof/closed socket and error?

Well, if the device closed without more data becoming available, the 
readyRead() signal will not be emitted. Therefore, waitForReadyRead cannot 
return true, since the signal wasn't emitted. So by necessity, it needs to 
return false.

> In view of the documentation it seems doubtful if this will process the
> last line if it is not newline terminated. In which case the last code
> line is superfluous, but how do we then process the last line?

The behaviour of the last line without a newline is fixed in Qt 4.4 and 
upwards.

> The code also  begs the question how waitForMore is implemented internally,
> ie what happens when some bytes are available but canReadLine returns false
> and thus readLine will not be called to consume them?

waitForReadyRead() waits for more bytes to become available, regardless of 
whether there are bytes already available for reading.

> But I have very little practical Qt experience yet, so maybe some one
> shows how this is supposed to done in Qt?

See above. And please upgrade to Qt 4.6.

-- 
Thiago Macieira - thiago (AT) macieira.info - thiago (AT) kde.org
  Senior Product Manager - Nokia, Qt Development Frameworks
      PGP/GPG: 0x6EF45358; fingerprint:
      E067 918B B660 DBD1 105C  966C 33F5 F005 6EF4 5358
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 190 bytes
Desc: This is a digitally signed message part.
Url : http://lists.qt-project.org/pipermail/qt-interest-old/attachments/20100503/bf023603/attachment.bin 


More information about the Qt-interest-old mailing list