Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

Check QDataStream data availability



  • Hi all,
    I use a QDataStream to get data from a socket this way:
    @
    QTcpSocket *socket;
    socket = ...... ;
    QDataStream in(socket);
    QString str;
    in >> str;
    ....
    ....
    @

    is there a way to check if there are some data to read ?

    I need something like this:
    @
    while (data_available)
    {
    in >> str;
    }
    @



  • Hi,

    did you try to read the documentation of QTcpSocket? if you follow the class hierarchy, you come to "QIODevice":http://doc.qt.nokia.com/latest/qiodevice.html which has some signals:

    • void aboutToClose ()
    • void bytesWritten ( qint64 bytes )
    • void readChannelFinished ()
    • void readyRead ()

    There are also some methods, that can be used:

    • qint64 bytesAvailable()
    • bool canReadLine () const


  • [quote author="Gerolf" date="1296729153"]Hi,

    did you try to read the documentation of QTcpSocket? if you follow the class hierarchy, you come to "QIODevice":http://doc.qt.nokia.com/latest/qiodevice.html which has some signals:

    • void aboutToClose ()
    • void bytesWritten ( qint64 bytes )
    • void readChannelFinished ()
    • void readyRead ()

    There are also some methods, that can be used:

    • qint64 bytesAvailable()
    • bool canReadLine () const
      [/quote]

    Yes I know.
    I can't use signal because I prefer to do all in the same function.
    canReadLine() doesn't works as expected because I have:
    @
    connect(socket, SIGNAL(readyRead()), SLOT(newData()));
    ....
    void newData()
    {
    while(socket_socket->canReadLine())
    {

    }
    ...
    }
    @
    and it never enter in the "while" .

    But bytesAvailable() do the works. I didn't know about it...

    @
    connect(socket, SIGNAL(readyRead()), SLOT(newData()));
    ....
    void newData()
    {
    while(socket->bytesAvailable())
    {
    QDataStream in(socket);
    QString str;
    in >> str;
    ....
    }
    ....
    }
    @

    Thanks, it solved!



  • You should connect the socket with the datastream only once. The chunks from the TCP socket might not be complete for the datastream to fulfill it's work.

    Also, you connect socket to the slot, but read from socket_socket in the slot.



  • [quote author="Volker" date="1296732271"]

    Also, you connect socket to the slot, but read from socket_socket in the slot.[/quote]

    My transcription error.



  • [quote author="Volker" date="1296732271"]You should connect the socket with the datastream only once. The chunks from the TCP socket might not be complete for the datastream to fulfill it's work.
    [/quote]

    It actually works but thanks for your suggestion.
    I changed with:
    @
    void newData()
    {
    QDataStream in(socket);
    while(socket->bytesAvailable())
    {

         QString str;
         in >> str;
         ....
    }
    

    ....
    }
    @



  • That's only little better, you still have the same problem between subsequent emits of the readyRead() signal. You should connect the socket to the datastream in the place where you get/create the socket and leave them connected for the livetime of the TPC connection.



  • [quote author="Volker" date="1296739471"]That's only little better, you still have the same problem between subsequent emits of the readyRead() signal. You should connect the socket to the datastream in the place where you get/create the socket and leave them connected for the livetime of the TPC connection.[/quote]

    So you suggest this:
    @
    QDataStream *in;
    void myClass::newConnectionFromClient()
    {
    QTcpSocket *socket;
    in = new QDataStream(socket);
    socket = m_tcpServer->nextPendingConnection();
    connect(socket, SIGNAL(readyRead()), SLOT(newData()));
    ...
    }

    void myClass::newData()
    {
    while(socket->bytesAvailable())
    {

         QString str;
         in >> str;
         ....
    }
    

    ....
    }

    @



  • In principle, yes. But make it in the correct order:

    @
    QDataStream *in = 0;
    void myClass::newConnectionFromClient()
    {
        QTcpSocket *socket = m_tcpServer->nextPendingConnection();
        in = new QDataStream(socket);
        connect(socket, SIGNAL(readyRead()), SLOT(newData()));
    ...
    }
    @

    In your version the variable socket is not initialized and can lead to application crashes when calling QDataStream(socket).

    Initialize your datastream variable in to 0 in the constructor and don't forget to delete it after you're done it (and setting in to 0 again) or delete it in the destructor (no problem to delete a null pointer, that's valid C++ and guaranteed to do nothing).



  • [quote author="Volker" date="1296741413"]In principle, yes. But make it in the correct order:

    @
    QDataStream *in = 0;
    void myClass::newConnectionFromClient()
    {
        QTcpSocket *socket = m_tcpServer->nextPendingConnection();
        in = new QDataStream(socket);
        connect(socket, SIGNAL(readyRead()), SLOT(newData()));
    ...
    }
    @

    In your version the variable socket is not initialized and can lead to application crashes when calling QDataStream(socket).

    Initialize your datastream variable in to 0 in the constructor and don't forget to delete it after you're done it (and setting in to 0 again) or delete it in the destructor (no problem to delete a null pointer, that's valid C++ and guaranteed to do nothing).[/quote]

    Thanks,
    I'm in dept with you.



  • Watch out when using QDataStream with sockets. Always remember that QDataStream has no means to recover from short reads and writes (which won't happen in case of QTcpSocket, but may happen with files or so). That's why many examples use a mixed approach, by serializing data on a QByteArray and the prepending the length of the byte array itself as an unsigned X bits integer. On receiver's side, you read X bits, then read the corresponding amount of bytes into a bytearray, then decode using QDataStream.



  • [quote author="peppe" date="1296809201"]Always remember that QDataStream has no means to recover from short reads and writes (which won't happen in case of QTcpSocket, but may happen with files or so)[/quote]
    Hi peppe,
    what do you mean with this?



  • What do you think
    @
    QDataStream ds(socket);
    QString string;
    ds >> string;
    @

    does if there's not enough data avaialable to read to successfully decode the string?



  • That's a good question.

    Should it append if the sender send the string with:
    @
    QDataStream stream(socket);
    QString string;
    stream << string;
    @
    ?



  • No, it just silently fails. Therefore: do not do that.


Log in to reply