PDA

View Full Version : TCP: Don't process until a whole packet is received



P@u1
10th June 2011, 11:40
Hi everyone,

before switchting to qt I used SFML for networking and there you have an sf::Packet class, in which you can insert data with the << operator and then you can send.
The good thing with that is that it automaticully makes sure that the whole packet will be received is received and not part by part.

I want to have the same behaviour with qt.

I thought about sending the packet size first and checking in readyRead if the amount of bytes availble is >= the packet size.

The client should not start to process the data until the whole packet is received.

The problem with that is that before actually writing data to the QDataStream I need to figure out, how big the whole packet will be in order to be able to send this information before sending anything else.
It would look something like this:


int packetSize = 0;
for(int i = 0; i < someVector.size(); ++i)
{
packetSize += someVector[i].getSize();
}
QDataStream stream(&socket);
stream << packetSize;
for(int i = 0; i < someVector.size(); ++i)
{
stream << someVector[i];
}


I would prefer a solution where the size is automaticully figured out and written before anything else.

With sfml it works like this:


sf:.Packet toSend;
for(int i = 0; i < someVector.size(); ++i)
{
toSend << someVector[i];
}
socket.Send(toSend);

Then on the client side


sf::Packet toReceive;
if(socket.Receive(toReceive) != sf::Socket::Done)
{
//not all data received yet, try again next time
}
else
{
//whole packet is there now, go and process it.
}

The packet automaticully measures the size of its contents and sends it before sending the actual data so that the client knows how to figure out when the whole packet is received.

Is there maybe some solution for qt to achieve this or something similar?

Thanks for help in advance!

wysota
10th June 2011, 12:11
The simplest self-contained thing that comes to my mind:


class DataBlock {
public:
DataBlock() {
clear();
}
void clear() {
m_buf.close();
m_buf.open(QIODevice::WriteOnly);
m_stream.setDevice(&m_buf);
}
void writeTo(QIODevice *dev) {
QByteArray dat = m_buf.data();
quint32 s = dat.size();
quint32 sNetwork = qToBigEndian(s);
QByteArray sizeBlob = QByteArray((const char*)&sNetwork, 4);
dev->write(sizeBlob);
dev->write(dat);
}
bool readFrom(QIODevice *dev) {
m_stream.setDevice(0);
if(dev->bytesAvailable()<4) return false;
QByteArray sizeBlob = dev->peek(4);
quint32 size = qFromBigEndian(*((quint32)sizeBlob.constData()));
if(dev->bytesAvailable()<4+size) return false;
QByteArray data = dev->read(size);
m_buf.setData(data);
m_buf.open(QIODevice::ReadOnly);
m_stream.setDevice(&m_buf);
}
QDataStream& stream() { return m_stream; }
private:
QDataStream m_stream;
QBuffer m_buf;
};

Disclaimer: not tested!