PDA

View Full Version : QTcpSocket: Sending multiple strings results in errors... sometimes.



seanlo
16th December 2010, 08:28
Hey everyone,

Using the fortune server and client as a base, my program sends and receives strings fine. However, when i start sending multiple strings, very fast, they come out combined.

For example: Sending a string of "12345", loop this 100x without any delay, sometimes what comes out on the other end is 123451234512345. Sometimes..

Here's what i used for the client side:

clientSocket->write("12345");
clientSocket->flush();

Meanwhile on the server, using the readyRead() slot:
QString testString=fromClient->readAll();
qDebug()<<"Received:"<<testString<<"\nLength:"<<testString.length();

Note:
If i connect to myself: 127.0.0.1, no errors.
If i set a high delay (100ms+), no errors.

My program requires me to send as much/fast data as possible, so 100+ ms delays isn't an option.
Is creating a buffer and figuring out how to point and where to read my only option at this point? :(

tbscope
16th December 2010, 08:43
That's normal, you don't provide any structure.

If I send 100 bytes, 100 bytes get received.

A basic technique you can apply is to put a line break after each write. That way, you can at least parse lines.
For more complex structures, you need a structure. Take a look at HTML of NNTP for example. Or XML, QDataStream or similar.

seanlo
17th December 2010, 02:39
Hey Tbscope,

That's the catch though.. i send 100 bytes in an infinite loop, most packets come out to be 100 bytes, some come out at 200, 300, 400, 1000, 10000 etc etc...

I don't understand why that would be normal, an explanation would be really helpful to this newbie. :)

I've thought of parsing it out with a text line break, but i don't know how to make it work when an image needs to come after the string. I've also used QDataStream before i posted this error, it results in the same thing as above. Some packets come out combined. :(

squidge
17th December 2010, 08:56
The only come out seperated because there is a certain amount of time between each packet, but even then, its not guaranteed. You may even get packets shorter than you send sometimes. This is because of how TCP works over IP, for more details you should read the official documentation about how data travels - the RFC document may help you here: http://tools.ietf.org/html/rfc1122

If you want to know when a packet starts and another finishes, you need to packetise the data.

Eg. You could send something xml-like like "<data length=32 type=text>aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa</data>" or "<data length=912272 type=image>...</data>"

seanlo
21st December 2010, 02:48
Using an XML based structure solved the problem of repeated strings. I've then tried it with a base 64 - binary image. It's fine for small images, it no longer works for large images. (since the packets are broken up)

Don't suppose you have any suggestions? I can't figure out how to get bytesAvailable working for this scenario. bytesAvailable worked great when i don't send a lot of data.. When i send about 15-20 frames of 1440x900 per second, it no longer works.

Example:

if (fromClient->bytesAvailable()<someSize)
{
return;
}

where fromClient = socket, and someSize is the size of the image. Let's say the image size is 60 k.

Now, the initial package that arrives with the image information tells it to wait to 60 k.
However, it doesn't only reach 60, it reaches 80 k. (in addition with the next incoming package).
How do i proceed? 0_o
Manually read it to 60? I don't know how to actually code this part... i've been trying but no luck.

Any suggestions are welcome. :)

Thanks!
Sean.

tbscope
21st December 2010, 08:28
You really should learn how TCP works.

If you need to send a large amount of data, it will always be received in packets. You need to stitch those packets together.
How to do that? There are a few techniques, among them are:
1. Before receiving a large package let the receiver know the size.
2. After receiving a large package let the receiver know the end (by some keyword for example)

If you use XML already, that's extremely simple, everything is in place for you to know the end. It's the closing tag of the image.
And, it gets even better, if you use an xml stream reader, it will be easier still.

seanlo
22nd December 2010, 04:20
Welp i managed to get it to work after trying out XML for the past few days. I used a combination of:

XML + base64 + text parsing.

I had a <ENDIMAGE/> to signal the end of one XML picture(base64). Anything after that which comes in combined with the other packets gets attached to another byteArray. In essence, creating my own byteArray buffer was the solution.

Thanks everyone for your suggestions. :)