I worked on a project that does what you expect, see here the solution that I developed to our problems, simplified to be easier to understand:
Edited, added support to the server deal with multiple clients.
Client.h:
#include <QtCore>
#include <QtNetwork>
class Client : public QObject
{
Q_OBJECT
public:
explicit Client(QObject *parent = 0);
public slots:
bool connectToHost(QString host);
bool writeData(QByteArray data);
private:
QTcpSocket *socket;
};
Client.cpp:
#include "client.h"
static inline QByteArray IntToArray(qint32 source);
Client::Client(QObject *parent) : QObject(parent)
{
socket = new QTcpSocket(this);
}
bool Client::connectToHost(QString host)
{
socket->connectToHost(host, 1024);
return socket->waitForConnected();
}
bool Client::writeData(QByteArray data)
{
if(socket->state() == QAbstractSocket::ConnectedState)
{
socket->write(IntToArray(data.size())); //write size of data
socket->write(data); //write the data itself
return socket->waitForBytesWritten();
}
else
return false;
}
QByteArray IntToArray(qint32 source) //Use qint32 to ensure that the number have 4 bytes
{
//Avoid use of cast, this is the Qt way to serialize objects
QByteArray temp;
QDataStream data(&temp, QIODevice::ReadWrite);
data << source;
return temp;
}
Server.h:
#include <QtCore>
#include <QtNetwork>
class Server : public QObject
{
Q_OBJECT
public:
explicit Server(QObject *parent = 0);
signals:
void dataReceived(QByteArray);
private slots:
void newConnection();
void disconnected();
void readyRead();
private:
QTcpServer *server;
QHash<QTcpSocket*, QByteArray*> buffers; //We need a buffer to store data until block has completely received
QHash<QTcpSocket*, qint32*> sizes; //We need to store the size to verify if a block has received completely
};
Server.cpp:
#include "server.h"
static inline qint32 ArrayToInt(QByteArray source);
Server::Server(QObject *parent) : QObject(parent)
{
server = new QTcpServer(this);
connect(server, SIGNAL(newConnection()), SLOT(newConnection()));
qDebug() << "Listening:" << server->listen(QHostAddress::Any, 1024);
}
void Server::newConnection()
{
while (server->hasPendingConnections())
{
QTcpSocket *socket = server->nextPendingConnection();
connect(socket, SIGNAL(readyRead()), SLOT(readyRead()));
connect(socket, SIGNAL(disconnected()), SLOT(disconnected()));
QByteArray *buffer = new QByteArray();
qint32 *s = new qint32(0);
buffers.insert(socket, buffer);
sizes.insert(socket, s);
}
}
void Server::disconnected()
{
QTcpSocket *socket = static_cast<QTcpSocket*>(sender());
QByteArray *buffer = buffers.value(socket);
qint32 *s = sizes.value(socket);
socket->deleteLater();
delete buffer;
delete s;
}
void Server::readyRead()
{
QTcpSocket *socket = static_cast<QTcpSocket*>(sender());
QByteArray *buffer = buffers.value(socket);
qint32 *s = sizes.value(socket);
qint32 size = *s;
while (socket->bytesAvailable() > 0)
{
buffer->append(socket->readAll());
while ((size == 0 && buffer->size() >= 4) || (size > 0 && buffer->size() >= size)) //While can process data, process it
{
if (size == 0 && buffer->size() >= 4) //if size of data has received completely, then store it on our global variable
{
size = ArrayToInt(buffer->mid(0, 4));
*s = size;
buffer->remove(0, 4);
}
if (size > 0 && buffer->size() >= size) // If data has received completely, then emit our SIGNAL with the data
{
QByteArray data = buffer->mid(0, size);
buffer->remove(0, size);
size = 0;
*s = size;
emit dataReceived(data);
}
}
}
}
qint32 ArrayToInt(QByteArray source)
{
qint32 temp;
QDataStream data(&source, QIODevice::ReadWrite);
data >> temp;
return temp;
}
Note: Do not use this method to transfer large files because with this method the entire contents of the message is put inside the memory before sent and this causes a high memory usage. And because 32 bits signed INT has max value to 2,147,483,647, if your input data has a value higher than that in bytes it won't work. Take care.