PDA

View Full Version : QTcpSocket - making sure all data was sent



eliben
10th July 2011, 03:51
I'm integrating socket comms into a dialog, and have a question about ensuring that all data was sent when using QTcpSocket::write. My approach to this is the following:


When meaning to send (say, a QByteArray), call QTcpSocket::write
Connect a slot to the bytesWritten signal, where I increment an internal counter with the amount of bytes sent so far, and if bytesToWrite() == 0, more data needs to be sent
When sending "more data", use the counter to index into the buffer to send the rest of it.
The previous two steps will be invoked over and over until all data is sent.


Is this the correct way of ensuring the whole buffer gets sent eventually? Is there an easier way?

Thanks in advance

ChrisW67
10th July 2011, 07:47
Unless the connection is abnormally or deliberately terminated all the bytes written will be sent. Qt and your operating system TCP stack looks after things like queuing, window sizes, ensuring "optimal" pipelines, and ensuring that bytes are received intact.

eliben
10th July 2011, 08:42
ChrisW67 - thanks for your reply,

However, I know it is good practice in most languages (including the lowest-level 'send' function from the socket C API) to check this return value (for non-blocking calls). The manual page of 'send' says that a partial write may be returned if the message doesn't fit into the send buffer. This can happen if the network is congested for some reason, or the receiving side doesn't ack fast enough.

Do you intend to imply this *never* really happens?

ChrisW67
10th July 2011, 09:40
Every byte that a QIODevice/QTCPSocket accepts for sending will be sent barring abnormal termination. That is not to say that every byte offered will be accepted for sending, i.e. QIODevice::write() may return a positive number smaller than the number of bytes offered. You have to handle that if it is likely to apply. I've never seen it myself, but I only send short messages generally.

I read your initial question as if you were trying to coopt the TCP windowing mechanisms. I think waiting until all the bytes accepted have been sent before offering more bytes is sub-optimal. You are waiting for an empty buffer rather than trying to keep the send buffer near-full. By keeping the send buffer near-full you ensure that Qt and OS can operate normally with respect to the throughput regulation mechanisms in TCP. You might like to add more data to the queue every time bytesSent() is received, or only after x KB are sent (an adaptation of your original suggestion).

eliben
10th July 2011, 12:33
Every byte that a QIODevice/QTCPSocket accepts for sending will be sent barring abnormal termination. That is not to say that every byte offered will be accepted for sending, i.e. QIODevice::write() may return a positive number smaller than the number of bytes offered. You have to handle that if it is likely to apply. I've never seen it myself, but I only send short messages generally.

I read your initial question as if you were trying to coopt the TCP windowing mechanisms. I think waiting until all the bytes accepted have been sent before offering more bytes is sub-optimal. You are waiting for an empty buffer rather than trying to keep the send buffer near-full. By keeping the send buffer near-full you ensure that Qt and OS can operate normally with respect to the throughput regulation mechanisms in TCP. You might like to add more data to the queue every time bytesSent() is received, or only after x KB are sent (an adaptation of your original suggestion).

The thing is, I also have just relatively short packages to send. But I want to be 100% sure they are actually sent, so the two options are either what I originally wrote, or loop on ::write until it reports all send. The latter doesn't play with the GUI event loop well.

Perhaps my approach is an overkill, but it will only be triggered in very rare cases so maybe that's not too bad?