PDA

View Full Version : (SOLVED) Data loss over tcp connection?



giowck
24th September 2009, 15:19
Hi,

Sometimes the packets i send over the network seems to get lost O.o
On the local machine all works fine... But not over the internet.

Client:


QByteArray database = inFile.readAll();

QByteArray outBlock;
QDataStream out(&outBlock, QIODevice::WriteOnly);
out.setVersion(QDataStream::Qt_4_5);
out << qint64(0) << serverPass << quint16(GET_DB) << database;
out.device()->seek(0);
out << qint64(outBlock.size() - sizeof(qint64));

tcpSocket.write(outBlock);


Now before i send that packet i check the size od database(QByteArray)and it is correct!

Server code:



QDataStream inStream(tcpSocket);
inStream.setVersion(QDataStream::Qt_4_5);

/* packet format */
qint64 size2;
QString serverPass2;
quint16 reqType2;
QByteArray data2;

inStream >> size2 >> serverPass2 >> reqType2 >> data2;


now i recive all data correctly except data2 (database) which is a QByteArray with size == 0! But that's not possible, so where is the data? The outgoing array(database) whas not empty...

Is it possible to loose data over tcp??

caduel
24th September 2009, 16:26
data is transmitted in packages over the network. when you get notified (by a Qt signal) that data is available, this means SOME data, not necesarrily ALL data you expect.

You have to wait til the complete package has arrived (which is why you send the package size first, so you know when you have all the data). Only then may you use >> to read the data into your QByteArray.

See the various demos (fortune-client, I think is one) shipped with Qt that illustrate this.
There should be several threads in this forum, too. Search it.

HTH

giowck
24th September 2009, 17:44
thanks for your answer. I looked at the source code from various examples... The problem is that i need a blocking function (no signals like readyRead() ...)

i only use socket.waitForReadyRead()... So how can i continue the function block only if i have all data?

Something like:



...
socket.waitForReadyRead();

inStream >> size;

if (size > socket.bytesAvailable())
socket.waitForReadyRead();

instream >> database;
...

?

Sorry im new at network programming :o

caduel
24th September 2009, 19:57
well, while-loops are not network-specific, are they?

code taken from fortune client example


const int Timeout = 5 * 1000;

// wait for blocksize to arrive
while (socket.bytesAvailable() < (int)sizeof(quint16)) {
if (!socket.waitForReadyRead(Timeout)) {
emit error(socket.error(), socket.errorString());
return;
}
}

// read blockSize
quint16 blockSize;
QDataStream in(&socket);
in.setVersion(QDataStream::Qt_4_0);
in >> blockSize;
// blocksize does not include "itself"

// now we know how much data has to arrive in total
// wait for rest of the block...
while (socket.bytesAvailable() < blockSize) {
if (!socket.waitForReadyRead(Timeout)) {
emit error(socket.error(), socket.errorString());
return;
}

// now we are sure that no 'short reads' can happen
instream >> database;


you have to take care if blockSize is the size of the complete package (including the 2 bytes of the quint16 of blocksize itself) or just the data part's size. in the fortune server example blocksize is only the data part

HTH

giowck
24th September 2009, 20:04
Hey thanks... BTW i solved the problem with this loop:



qint64 size;
QString serverPass;
quint16 reqType;
QByteArray data;

in >> size;

while (tcpSocket->bytesAvailable() < size) {
if (!tcpSocket->waitForReadyRead()) {
qDebug() << "Not enough bytes!";
disconnectFromServer();
return false;
}
}

in >> serverPass >> reqType >> data;


THANKS!!! :D:D