OK I have got it - basically the client was disconnecting the socket right after it had written everything so the server was getting a mangled message.
I added:
socket.waitForDisconnected(5000);
socket.waitForDisconnected(5000);
To copy to clipboard, switch view to plain text mode
Is there a better way to get the client to wait until the data has been read?
I also had to move all the server variables outside the slot attached to the readyRead function as the datastream and other variables were being re-created each time the function was called.
As an aside - is my method of using a QVariant bad practice ? I would assume that it is time consuming to cast each type into and out of a QVariant with a heavy load. Would it be better to use separate sockets for the different types?
Here is the end code:
Server:
{
connect(this, SIGNAL(readyRead()), this, SLOT(readClient()));
connect(this, SIGNAL(disconnected()), this, SLOT(deleteLater()));
blockSize_8 = 0;
blockSize_16 = 0;
blockSize_32 = 0;
blockSize_64 = 0;
version = 0;
data = 0;
endFlag = 0x0;
in.setDevice(this);
}
ServerSocket::~ServerSocket()
{
in.unsetDevice();
}
void ServerSocket::ServerSocket()
{
if (blockSize_64 == 0) {
if (bytesAvailable() < (sizeof(quint64) + sizeof(quint8)))
return;
in >> blockSize_64;
in >> version;
}
if (bytesAvailable() < (quint64)(blockSize_64 + sizeof(quint16)))
return;
in >> description;
in >> data;
in >> endFlag;
"\n\tType(" + QString(data.
typeName()) + "): " + QString::number(data.
type()) + "\n\tSize: " + QString::number(blockSize_64
) + "\n\tMessage: " + description +
"\n\tData: " + data.toString() +
"\n\tEndFlag: " + QString::number(endFlag
);
switch (data.type()) {
//just for testing the image gets there OK
label
->setPixmap
(QPixmap::fromImage(data.
value<QImage>
()));
label->show();
break;
break;
default:
break;
}
emit message(emit_message, Server::DATA);
ServerSocket::ServerSocket(QObject *parent) : QTcpSocket(parent)
{
connect(this, SIGNAL(readyRead()), this, SLOT(readClient()));
connect(this, SIGNAL(disconnected()), this, SLOT(deleteLater()));
blockSize_8 = 0;
blockSize_16 = 0;
blockSize_32 = 0;
blockSize_64 = 0;
version = 0;
data = 0;
description = QString();
endFlag = 0x0;
in.setDevice(this);
in.setVersion(QDataStream::Qt_4_5);
}
ServerSocket::~ServerSocket()
{
in.unsetDevice();
}
void ServerSocket::ServerSocket()
{
if (blockSize_64 == 0) {
if (bytesAvailable() < (sizeof(quint64) + sizeof(quint8)))
return;
in >> blockSize_64;
in >> version;
}
if (bytesAvailable() < (quint64)(blockSize_64 + sizeof(quint16)))
return;
in >> description;
in >> data;
in >> endFlag;
QString emit_message = "\n\tVersion: " + QString::number(version) +
"\n\tType(" + QString(data.typeName()) + "): " + QString::number(data.type()) +
"\n\tSize: " + QString::number(blockSize_64) +
"\n\tMessage: " + description +
"\n\tData: " + data.toString() +
"\n\tEndFlag: " + QString::number(endFlag);
QLabel * label;
switch (data.type()) {
//just for testing the image gets there OK
case QVariant::Image:
label = new QLabel();
label->setPixmap(QPixmap::fromImage(data.value<QImage>()));
label->show();
break;
case QVariant::String:
break;
default:
break;
}
emit message(emit_message, Server::DATA);
To copy to clipboard, switch view to plain text mode
Client:
void Client::sendRequest()
{
socket.connectToHost(serverName, serverPort);
if (!socket.waitForConnected(TIMEOUT)) {
emit error(socket.error(), socket.errorString());
return;
}
if (text == "image") {
data
= QImage("someimage.jpg");
description = "This is an image";
}
else {
data = text;
description = "This is some text";
}
//block size << version number << description.
out << quint64(0) << quint8(1) << description;
//data << end flag
out << data << quint16(0xFFFF);
out.device()->seek(0);
//block size is description + data
out << quint64(block.size() - sizeof(quint64) - sizeof(quint8) - sizeof(quint16));
socket.write(block);
socket.flush();
qDebug
() <<
"Sending: [" + description
+ QVariant(text
).
toString() + "] to server(" + serverName
+ ":" + QString::number(serverPort
) + ")";
"\n\tType(" + QString(data.
typeName()) + "): " + QString::number(data.
type()) + "\n\tSize: " + QString::number(quint64
(block.
size() - sizeof(quint16
) - sizeof(quint8
) - sizeof(quint16
))) + "\n\tMessage: " + description +
"\n\tData: " + data.toString() +
"\n\tEndFlag: " + QString::number(quint16
(0xFFFF
));
qDebug() << emit_message;
socket.waitForDisconnected(5000);
socket.disconnectFromHost();
}
void Client::sendRequest()
{
QTcpSocket socket;
socket.connectToHost(serverName, serverPort);
if (!socket.waitForConnected(TIMEOUT)) {
emit error(socket.error(), socket.errorString());
return;
}
QVariant data;
QString description;
if (text == "image") {
data = QImage("someimage.jpg");
description = "This is an image";
}
else {
data = text;
description = "This is some text";
}
QByteArray block;
QDataStream out(&block, QIODevice::WriteOnly);
out.setVersion(QDataStream::Qt_4_5);
//block size << version number << description.
out << quint64(0) << quint8(1) << description;
//data << end flag
out << data << quint16(0xFFFF);
out.device()->seek(0);
//block size is description + data
out << quint64(block.size() - sizeof(quint64) - sizeof(quint8) - sizeof(quint16));
socket.write(block);
socket.flush();
qDebug() << "Sending: [" + description + QVariant(text).toString()
+ "] to server(" + serverName + ":" + QString::number(serverPort) + ")";
QString emit_message = "\n\tVersion: " + QString::number(quint8(1)) +
"\n\tType(" + QString(data.typeName()) + "): " + QString::number(data.type()) +
"\n\tSize: " + QString::number(quint64(block.size() - sizeof(quint16) - sizeof(quint8) - sizeof(quint16))) +
"\n\tMessage: " + description +
"\n\tData: " + data.toString() +
"\n\tEndFlag: " + QString::number(quint16(0xFFFF));
qDebug() << emit_message;
socket.waitForDisconnected(5000);
socket.disconnectFromHost();
}
To copy to clipboard, switch view to plain text mode
Sorry I didn't mean to PM you..
I just saw your reply:
the initial quint16(0) is for the block size. The quint8(1) is the version number - this won't be hard coded in the end but is there for the possibility of backwards compatibility in the future.
However it seems to be working now..
Thanks for your input.
If you have any further pointers for this they would be greatly appreciated!
Bookmarks