Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. [SOLVED] QTcpSocket; readyRead only signaled once
Forum Updated to NodeBB v4.3 + New Features

[SOLVED] QTcpSocket; readyRead only signaled once

Scheduled Pinned Locked Moved General and Desktop
7 Posts 3 Posters 7.3k Views 1 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • S Offline
    S Offline
    Sniperchang
    wrote on last edited by
    #1

    I'm witting an app which connects to a server via TCP. I have a class which handles the TCP connection. This class connects to host on creation and connects the readyRead signal to a slot called PacketRx. PacketRX is simply a while(tcp->bytesAvailable()){ tcp->readAll() } loop.

    When I first run the app, the readyRead signal is emitted on the first packet received. But when another packet comes in readyRead never gets signaled again. I've confirmed that data is coming in, I see it in wireshark, and if I place a blocking read call, the data is definitely coming in when it is supposed to.

    In the documentation, it does mention that "readyRead() is not emitted recursively; if you reenter the event loop or call waitForReadyRead() inside a slot connected to the readyRead() signal, , the signal will not be reemitted." Does this mean that it is not working because when returning from the PacketRX function, it is returning to the event loop of my application? If so, how am I supposed to use non-blocking calls if this is the behavior of readyRead?

    Thanks in advance!

    1 Reply Last reply
    0
    • K Offline
      K Offline
      koahnig
      wrote on last edited by
      #2

      Welcome to devnet

      You might like to have a look to the fortune "client":http://qt-project.org/doc/qt-5/qtnetwork-fortuneclient-example.html and "server":http://qt-project.org/doc/qt-5/qtnetwork-fortuneserver-example.html example.

      They give you a good overview for using clients and server with Qt

      Vote the answer(s) that helped you to solve your issue(s)

      1 Reply Last reply
      0
      • D Offline
        D Offline
        DBoosalis
        wrote on last edited by
        #3

        Please post your code where you create the TCP socket, connect the signal and slots, as well as the read code.

        1 Reply Last reply
        0
        • S Offline
          S Offline
          Sniperchang
          wrote on last edited by
          #4

          [quote author="koahnig" date="1417723355"]Welcome to devnet

          You might like to have a look to the fortune "client":http://qt-project.org/doc/qt-5/qtnetwork-fortuneclient-example.html and "server":http://qt-project.org/doc/qt-5/qtnetwork-fortuneserver-example.html example.

          They give you a good overview for using clients and server with Qt[/quote]

          Thanks, I'll keep an eye out for similar examples using non-blocking calls.

          [quote author="DBoosalis" date="1417725552"] Please post your code where you create the TCP socket, connect the signal and slots, as well as the read code. [/quote]

          Basically I have a class with this in the constructor:

          @tcp = new QTcpSocket(this);
          tcp->connectToHost( QHostAddress((quint32)addr), TCP_PORT, QIODevice::ReadWrite );
          connect(tcp, SIGNAL(readyRead()), this, SLOT(PacketRx()), Qt::AutoConnection);
          connect(tcp, SIGNAL(stateChanged(QAbstractSocket::SocketState)), this, SLOT(DataChanged()), Qt::AutoConnection);@

          Where QTcpSocket* tcp is a member of the class, and DataChanged deals with providing UI feedback on connection state.

          The PacketRX slot looks like this:
          @QByteArray rxdata;
          while(tcp->bytesAvailable()){
          rxdata = tcp->readAll();
          if(rxdata.isEmpty()) return;
          /* Do stuff with data */
          }
          @

          Seems straight forward to me. But PacketRX is only ever called once, so the stateChanged signal is only ever signaled the first time a data packet is received. When new packets come in, nothing.

          No issues with outgoing packets, the write call works fine.

          1 Reply Last reply
          0
          • D Offline
            D Offline
            DBoosalis
            wrote on last edited by
            #5

            That readAll in a loop might be the problem as it coulbe be reading all the data from both writes. If server & client are on the same machine and messages are small it is ok to use readAll but for going across a network you should make your client server a bit more robust.

            It would be a good idea to put at the start of each message how many bytes are in this message (see Qt Examples/Network/fortune/server. This way the socket knows when it can process the message in case more bytes need to be sent (Remember the network layer will break up the message anyway it sees fit and may sent your message in multiple packets)

            If you have control of both sender and receiver always put the size of the message at the front. This tells the reader how many bytes to expect.

            Using QDataStream this would be for the sender:

            @QByteArray ba;
            QDataStream out(&bba, QIODevice::WriteOnly);
            out << (quint32)0; // let QT do network conversion
            out << symbolName; // assuming QString
            out << dateTime; // assuming QDateTime
            out << strList;
            .
            .
            .
            out.device()->seek(0);
            out << (quint32)(bba.size() - sizeof(quint32));
            socket->write(ba); @

            Then for your read:
            @QByteArray ba;
            QDataStream in(socket);
            if (blockSize == 0) { // blockSize initiatally set to 0 by your app
            qint64 BytesAvailable = bytesAvailable();
            if (BytesAvailable < sizeof(quint32)) {
            qWarning() << "\Not enough bytes to read quint32"
            return;
            }
            in >> blockSize;
            }

            if (bytesAvailable() < blockSize) {
            qDebug() << "\nbytes availiable less then block size";
            return;
            }
            blockSize = 0; // set to zero for next message
            // have whole message here so we read and parse data from socket
            in >> symbolName;
            in >> mydateTime;
            in >> strList;
            .
            .
            .@

            Nice about this is we also let Qt do all the serializing and deserialising of the data. and you do not have to count bytes yourself to decompose your message.

            Hope this is of some value to you. One more thing put your connetToHost call after your connects()

            1 Reply Last reply
            0
            • S Offline
              S Offline
              Sniperchang
              wrote on last edited by
              #6

              [quote author="DBoosalis" date="1417730730"]That readAll in a loop might be the problem as it coulbe be reading all the data from both writes.[/quote]

              Good thought, but it's not that. I made sure the slot returns before sending another packet from the server. Once the slot returns, it never comes back.

              I actually didn't have the loop before. I was thinking perhaps if another packet is sitting in the buffer, that readyRead wouldn't signal anymore. But adding the loop didn't make a difference.

              [quote author="DBoosalis" date="1417730730"]If server & client are on the same machine and messages are small it is ok to use readAll but for going across a network you should make your client server a bit more robust.[/quote]

              Thank for the tip, I intended to fix up my read process later, but it's not a concern for now since readyRead wasn't behaving the way I thought it should.

              [quote author="DBoosalis" date="1417730730"]One more thing put your connetToHost call after your connects()[/quote]

              Good catch, thanks!

              1 Reply Last reply
              0
              • S Offline
                S Offline
                Sniperchang
                wrote on last edited by
                #7

                Fixed, turned out to be an issue with the server. The server was not replying to messages until a TCP reset occurred, then it would start replying to messages again, but at that time readyRead would not fire. Fixing the server seemed to have fixed to readyRead issue.

                Thanks for the help!

                1 Reply Last reply
                0
                • mariappanM mariappan referenced this topic on

                • Login

                • Login or register to search.
                • First post
                  Last post
                0
                • Categories
                • Recent
                • Tags
                • Popular
                • Users
                • Groups
                • Search
                • Get Qt Extensions
                • Unsolved