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] Using QTcpSocket::write(QByteArray) several times - only sends the first time.
Qt 6.11 is out! See what's new in the release blog

[Solved] Using QTcpSocket::write(QByteArray) several times - only sends the first time.

Scheduled Pinned Locked Moved General and Desktop
12 Posts 4 Posters 17.9k 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.
  • A Offline
    A Offline
    Aerius
    wrote on last edited by
    #1

    Following scenario: I want to be able to send and recieve messages via QTcpSocket from a server to a client and vice versa. To do this, I implemented several methods to be able to encode different objects into a QDataStream. The client connects to the server, the server stores the respective QTcpSocket and is then ready to send a recieve messages.

    The methods utilize this schema:

    @void ServerConnection::send( Player *reciever, QString identifier, QString text ) {

    QTcpSocket *client = getClient( reciever ); // simply looks up which QTcpSocket goes with the corresponding player. No fancy implementation details here.
    
    if ( client == 0 ) {
        return;
    }
    
    QByteArray block;
    QDataStream out(&block, QIODevice::WriteOnly);
    out.setVersion(QDataStream::Qt_5_0);
    out << (quint16)0;
    
    // send an identifier
    out << identifier;
    
    // send the data
    out << text;
    
    out.device()->seek(0);
    out << (quint16)(block.size() - sizeof(quint16));
    
    client->write(block);
    

    }@

    The client responds in this way to messages sent to it:

    @void ClientConnection::readNewData() {

    qint16 blockSize = 0;
    
    QDataStream in(_tcpSocket);
    in.setVersion(QDataStream::Qt_5_0);
    
    if (blockSize == 0) {
        if (_tcpSocket->bytesAvailable() < (int)sizeof(quint16))
            return;
    
        in >> blockSize;
    }
    
    if (_tcpSocket->bytesAvailable() < blockSize)
        return;
    
    QString identification;
    in >> identification;
    
    if ( identification == "Request" ) {
    
        QString type;
        in >> type;
    
        if ( type == "Identification" ) {
            send((QString)"Identification", (QString)"Emerald Player");
        } else if ( type == "CompanyName") {
            send((QString)"CompanyName", _player->companyName());
        } else if ( type == "CEOName" ) {
            send((QString)"CEOName", _player->ceoName());
        } else {
            qDebug() << "Recieved unknown Request";
            qDebug() << type;
        }
    } else if ( identification == "Player") {
        _player->decode(&in);
    } else if ( identification == "Finance") {
    
    } else if (/* yatta yatta - several differente else-ifs here */) {
    
    } else {
        qDebug() << "Recieved unknown Identification token.";
        qDebug() << identification;
    }
    

    }
    @

    Now, I want to invoke the send method several times, e.g., like this:

    @void ServerConnection::doStuff() {

    // do irrelevant stuff
    
    send(player, (QString)"Request", (QString)"CompanyName");
    send(player, (QString)"Request", (QString)"CEOName");
    

    }@

    As you can see, I just invoke the sending process twice. However, Qt decides to send only once. Both send commands work perfectly on their own, invoking them right after each other leads to only the first one beeing sent and recieved.

    I tried to add client->flush() right after client->write(block) to no avail, I tried to invoke client->waitForBytesWritten() right before client->write(block) and I tried both, to no avail. I propably didn't quite understand how waitForBytesWritten() works, so I guess I'm not utilizing it right. However, I fail to see how exactely this is to be done.

    I cannot just add these two messages into one, simply because I want to be able to encode lots of different objects and I need to be flexible on when sending what.

    Any help explaining how to make sure I can utilize several write() commands after each other would be extremely appreciated.

    1 Reply Last reply
    0
    • Q Offline
      Q Offline
      qxoz
      wrote on last edited by
      #2

      Try put
      @client->waitForBytesWritten(3000);@
      after
      @client->write(block);@
      And look what happened.

      1 Reply Last reply
      0
      • Q Offline
        Q Offline
        qxoz
        wrote on last edited by
        #3

        In my opinion better use request-response type communications. But correct me if i'm wrong :).

        1 Reply Last reply
        0
        • A Offline
          A Offline
          Aerius
          wrote on last edited by
          #4

          Tried to use waitForBytesWritten() after sending, no change.

          Can you elaborate your second statement? Do you mean I should explicitely wait until I got a response until I send again?

          1 Reply Last reply
          0
          • A Offline
            A Offline
            alexisdm
            wrote on last edited by
            #5

            The data is probably sent correctly, but the way your readNewData function is written means it can only treats one complete message.
            As TCP and Qt doesn't guarantee that "1 sent message = 1 readyRead signal", you need to handle the cases where you don't receive a complete message, and where you receive several messages for the same signal.

            @void ClientConnection::readNewData() {
            /* this has to be a class member, initialized to 0 when the connection opens /
            /
            quint16 blockSize = 0; */

            QDataStream in(_tcpSocket);
            in.setVersion(QDataStream::Qt_5_0);
            
            while(1) { 
            
                if (blockSize == 0) {
                    if (_tcpSocket->bytesAvailable() < (int)sizeof(blockSize))
                        return;
            
                    in >> blockSize;
                }
            
                if (_tcpSocket->bytesAvailable() < blockSize)
                    return;
            
               // read your message here
               // ...
            
               // reset for the next message       
               blockSize = 0;
            }
            

            }@

            1 Reply Last reply
            0
            • Q Offline
              Q Offline
              qxoz
              wrote on last edited by
              #6

              [quote author="Aerius" date="1360849229"]Do you mean I should explicitely wait until I got a response until I send again?[/quote]

              Well, it is referred.
              Look at incoming data probably you already read both messages at once.

              edit
              As alexisdm already wrote :).

              1 Reply Last reply
              0
              • A Offline
                A Offline
                Aerius
                wrote on last edited by
                #7

                [quote author="alexisdm" date="1360849664"]
                As TCP and Qt doesn't guarantee that "1 sent message = 1 readyRead signal"
                [/quote]

                Thank you, this was the core information I was missing. Your implementation also works perfectly, so thanks for that as well. :)

                1 Reply Last reply
                0
                • Q Offline
                  Q Offline
                  qxoz
                  wrote on last edited by
                  #8

                  Look at "http://www.youtube.com/watch?v=BWEIWViWFwI&list=SP2D1942A4688E9D63&index=70":http://www.youtube.com/watch?v=BWEIWViWFwI&list=SP2D1942A4688E9D63&index=70
                  there is very good solution for client server apps.

                  1 Reply Last reply
                  0
                  • A Offline
                    A Offline
                    andre
                    wrote on last edited by
                    #9

                    If you're passing a limited set of short messages, perhaps you can also consider using Qxt's RPC stuff. It allows you just use signals and slots across a network connection.

                    1 Reply Last reply
                    0
                    • Q Offline
                      Q Offline
                      qxoz
                      wrote on last edited by
                      #10

                      Seems Qxt is a really nice stuff. Andre have you try use any modules from it?

                      1 Reply Last reply
                      0
                      • A Offline
                        A Offline
                        andre
                        wrote on last edited by
                        #11

                        Yes, I have used it in the past.

                        1 Reply Last reply
                        0
                        • A Offline
                          A Offline
                          Aerius
                          wrote on last edited by
                          #12

                          Thanks for the tip Andre, I'll look into it. For the most part though, I'll be encoding and decoding objects of various sizes (see lines 36 to 41 in the second snip of code) and send them, so I guess the mechanism won't help me in that regard.

                          However, the mechanism sounds interesting, so maybe I can use that wherever I don't need to send whole objects across the network.

                          1 Reply Last reply
                          0

                          • Login

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