I discovered the issue: the QTcpSocket I had been trying to read from belonged to a different thread. Even though bytes were available according to the QIODevice's buffer, they could not be read because of this.
Therefore:
* Always ensure that the socket you want to read from belongs to the thread on which you want to do the reading *
To help with this, and as Taylor suggested above, one can take advantage of QTcpSocket's signals and slots infrastructure (preferred). This has the appropriate threading infrastructure in place and in theory should make things a lot simpler.
OR
Be super-cautious and
(a) utilize ones own QThread, moving the object that contains the QTcpSocket to this QThread
then,
(b) use the waitForReadyRead of the QTcpSocket in the blocking read loop of this other thread.
This latter approach is more difficult since if one wants to retain the QTcpSocket for other threads in future reads and writes, then after it has been moved to another thread and processed by that other thread, it must be moved back to the main thread before it can ever be moved a further thread. -- gives me a headache just trying to word that! Of course one might chose to keep the same QTcpSocket worker thread throughout so that it only has to be moved once, or simple creating a new QTcpSocket each time a QTcpSocket is required, moving it to its own QThread and then immediately deleting it when its finished with.
Basically, go for the first signals and slots method if you can.