Qt World Summit: Register Today!

[SOLVED] QTcpSocket, sending data with fast intervals

  • Hello,

    I've been testing client <-> server communications for few days now, and I've compiled some usable classes for my self to proceed with my project. I now face a problem though, I need to send messages from the server to client within a for loop, meaning with very fast intervals. Problem is, the client receives this data as concatenated string. Meaning, if server sends:

    @ for (int i = 0; i < 5; i++)
    connection->sendMessage("TEST " + QVariant(i).toString());

    connection is an object of the class I've made. sendMessage looks like this:

    @bool serverConnection::sendMessage(QString message)
    QVariant data = QVariant(message);
    if (this->socket->state() != QAbstractSocket::ConnectedState) throw std::string("Socket is not connected");
    if (this->socket->write(data.toByteArray()) == -1) throw std::string("Error while writing data to socket");
    if (!this->socket->waitForBytesWritten(20000)) throw std::string("Timeout while waiting for bytes to be written to socket");
    catch (std::string error)
    global_logs->write("Cannot send message " + message.toStdString() + " to remote host, error: " + error, logs::ERRORS, logs::ID_ERROR);
    global_logs->write("Socket last error: " + socket->errorString().toStdString(), logs::ERRORS, logs::ID_ERROR);
    return false;

    The client receives this as:

    Server XXX sends a message: TEST 1TEST 2TEST 3TEST 4

    I've tried much with flush() calls etc. but I just don't seem to get it.. I guess it's too fast for the socket to be ready, but how can I pause etc. in the sendMessage function, before sending another message? I thought waitForBytesWritten was supposed to do that?

  • You are using the wrong tool for the job. "TCP":http://www.wikipedia.org/wiki/Transmission_Control_Protocol gives you a pipe that you push bytes through. TCP guarantees that bytes put in come out the other end intact and in the correct order, or they don't come out at all. Note that the unit here is bytes, not messages, protocol data units, or any other high level construct: you are responsible for reassembling these.

    QTCPSocket::waitForBytesWritten() does not help you here. It returns when Qt has given the bytes to be sent to the operating system. The OS may then choose to buffer and send a TCP packet independently.

    If you need to send short, individual messages that arrive at the other end as the same short, individual messages then you should consider "UDP":http://www.wikipedia.org/wiki/User_Datagram_Protocol datagrams. With UDP a message (datagram) either arrives or does not arrive as a whole. You get no guarantees about order of arrival and you have to be willing to accept the possible loss or duplication of messages.

  • Thank you for your answer. As you probably noticed, I am new to handling packets etc, so I thank you for your clarification on them!

    Sadly, UDP is not something I can use here. I need to be sure the message has reached it's destination, as I'm creating a updater for my application at the moment. I've planned to query the server for files needed for the application (these are what I'm trying to send as individual TCP packets, I mean not the files itself, but the file names), and from them the client generates MD5 hashes of the files already present, and then cross checks the hashes with the server. After this, the client should know which files to download.

    So, it is critical that no packets are skipped. Ofcourse I could send all the files in one packet, separated with something, and then just parse it with the client. This is something I've thought about, and frankly didn't think it would be the best solution. But, is it? Basically I'm just trying to make sure I'm not postponing the problem, meaning I might stumble to this same problem somewhere else, where it isn't so easy to just use another solution :)

  • Moderators

    [quote author="Zerby" date="1388701002"]I could send all the files in one packet, separated with something, and then just parse it with the client. [/quote]Yes, that would be the best solution using pure TCP.

    For a higher-level, message-based communications protocol, see "KD SOAP":http://www.kdab.com/kdab-products/kd-soap/ (a 3rd-party library)

  • bq. I could send all the files in one packet, separated with something, and then just parse it with the client. This is something I’ve thought about, and frankly didn’t think it would be the best solution. But, is it?

    You are ultimately going to send the name and checksum of every file anyway. I don't see why you think this would be a problem.

    The list transfer time is likely to be dwarfed by the time to checksum all the files. In any case you don't have to wait for the reception of the entire list to start work on the files you have received.

  • Thank you all for your replies, this is now solved!

Log in to reply