c++qtqtcpsocket

Read from QTcpSocket using QDataStream


I need to send binary data through a QTcpSocket. I was thinking about using QDataStream, but I've encountered a problem - it silently fails if no data has arrived at the time I try to read.

For example if I have this code:

QString str;
stream >> str;

It will fail silently if no data is currently there in the socket. Is there a way to tell it to block instead?


Solution

  • I reworked the code from @Marek's idea and created 2 classes - BlockReader and BlockWriter:

    Sample usage:

    // Write block to the socket.
    BlockWriter(socket).stream() << QDir("C:/Windows").entryList() << QString("Hello World!");
    
    ....
    
    // Now read the block from the socket.
    QStringList infoList;
    QString s;
    BlockReader(socket).stream() >> infoList >> s;
    qDebug() << infoList << s;
    

    BlockReader:

    class BlockReader
    {
    public:
        BlockReader(QIODevice *io)
        {
            buffer.open(QIODevice::ReadWrite);
            _stream.setVersion(QDataStream::Qt_4_8);
            _stream.setDevice(&buffer);
    
            quint64 blockSize;
    
            // Read the size.
            readMax(io, sizeof(blockSize));
            buffer.seek(0);
            _stream >> blockSize;
    
            // Read the rest of the data.
            readMax(io, blockSize);
            buffer.seek(sizeof(blockSize));
        }
    
        QDataStream& stream()
        {
            return _stream;
        }
    
    private:
        // Blocking reads data from socket until buffer size becomes exactly n. No
        // additional data is read from the socket.
        void readMax(QIODevice *io, int n)
        {
            while (buffer.size() < n) {
                if (!io->bytesAvailable()) {
                    io->waitForReadyRead(30000);
                }
                buffer.write(io->read(n - buffer.size()));
            }
        }
        QBuffer buffer;
        QDataStream _stream;
    };
    

    BlockWriter:

    class BlockWriter
    {
    public:
        BlockWriter(QIODevice *io)
        {
            buffer.open(QIODevice::WriteOnly);
            this->io = io;
            _stream.setVersion(QDataStream::Qt_4_8);
            _stream.setDevice(&buffer);
    
            // Placeholder for the size. We will get the value
            // at the end.
            _stream << quint64(0);
        }
    
        ~BlockWriter()
        {
            // Write the real size.
            _stream.device()->seek(0);
            _stream << (quint64) buffer.size();
    
            // Flush to the device.
            io->write(buffer.buffer());
        }
    
        QDataStream &stream()
        {
            return _stream;
        }
    
    private:
        QBuffer buffer;
        QDataStream _stream;
        QIODevice *io;
    };