[Interest] TCP ACK with QDataStream -- OR: disconnect race condition detection

d3fault d3faultdotxbe at gmail.com
Sat Sep 8 13:47:05 CEST 2012

TCP is a reliable protocol, but I'm wondering if Qt's abstraction
around it allows me to use it reliably. I'm using a QDataStream around
a QTcpSocket, and before I stream out I first check that
QAbstractSocket::isValid() returns true and that
QAbstractSocket::state() == ConnectedState. This all sounds fine and
those two checks do in fact detect a disconnection... but the
asynchronous nature of networking means that the state could change
from ConnectedState to UnconnectedState before I am able to stream out
(even if it's just a few lines after the isValid() and state()
checks). It doesn't make sense to lock the socket in a connected
state... but that kind of atomicity is what I'm aiming for.

What is the best/safest method to use QTcpSocket reliably?

Is the qint64 that QIODevice::write() returns the key to this (if it's
-1 then I didn't get an ACK?)? I've played around with
QDataStream::status(), which uses that qint64 that QIODevice::write()
returns... but with no luck. The QDataStream::status() always returned
QDataStream::Ok, even when the checks for QAbstractSocket::isValid()
and QAbstractSocket::state() == ConnectedState failed. My guess is the
underlying QIODevice isn't getting closed when the peer disconnects
(either via abort() or disconnectFromHost())... but I also have a
slightly outdated version of Qt (4.8) so maybe that's a bug and it's
fixed now?

The best strategy I've come up with so far is to check
QAbstractSocket::isValid() and QAbstractSocket::state() ==
ConnectedState _AFTER_ I stream out. This way I can assume (*gulp*)
that the previous write didn't fail (and if it does, queue whatever
failed to re-send when the connection is re-established)... but then
there's the opposite race condition to worry about: that write might
have succeeded before QAbstractSocket entered UnconnectedState... so I
might send the same data twice thinking it failed if I'm not careful.

Another better, though slightly inefficient, way of writing reliably
would be to check isValid() and state() == ConnectedState both before
and after the write... but that just seems like an ugly hack imo.

What would you guys recommend?


More information about the Interest mailing list