You are not logged in.

Dear visitor, welcome to QtForum.org. If this is your first visit here, please read the Help. It explains in detail how this page works. To use all features of this page, you should consider registering. Please use the registration form, to register here or read more information about the registration process. If you are already registered, please login here.

1

Saturday, October 4th 2008, 4:05pm

QByteArray writing and reading problem

Hi all

I have two network applications, something like server and client. For using data ,writing and reading, I use plugins, dll files, main application ensures only network connection. In server application I write data to socket.

Source code

1
2
3
4
5
6
7
		QByteArray *array = new QByteArray();
		QDataStream streamOut(array, QIODevice::WriteOnly);
		streamOut.setVersion(QDataStream::Qt_4_4);
		
		streamOut << quint32(Data::PluginData) << pluginName << quint32(ProgramViewerMenu::NewImage) << shot.toImage();

	    socket->write(*array);


I write '2', "Program Viewer", which is QString, '1' and QImage.
In client application I want to read all data to QByteArray. Then read from the array first number '2' then pass array to another class where I read QString and then pass remaining data in QByteArray to plugin class where I want to read second number.

Source code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
void DataThread::run()
{
	QByteArray array = socket->readAll();
	QDataStream streamOut(array);
	streamOut.setVersion(QDataStream::Qt_4_4);
	
	quint32 dataType;
	streamOut >> dataType;
	qDebug() << "data thread dataType" << dataType;
	       
	if (dataType == Data::ServerData)
		emit serverData(array);
	if (dataType == Data::PluginData)
		emit pluginData(array);
}

...
connect(thread, SIGNAL(pluginData(QByteArray)), this, SIGNAL(pluginDataIn(QByteArray)));
connect(connection, SIGNAL(pluginDataIn(QByteArray)), plugins, SLOT(dataIn(QByteArray)));
...


Source code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
void Plugins::dataIn(QByteArray array)
{
	QDataStream streamOut(array);
	streamOut.setVersion(QDataStream::Qt_4_4);
	
	QString name;
	streamOut >> name;
		
	qDebug() << name;
	
	Menu *menu = menus.value(name);
	if(!menu)
	{
		qDebug() << "return menu";
		return;
	}
	menu->readData(array);
}


Source code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
void ProgramViewerMenu::readData(QByteArray array)
{
	if (!isListening)
		return;
	
	window->getData(array);
	showWindow();
}

void ViewerWindow::getData(QByteArray array)
{
	QDataStream streamOut(array);
	streamOut.setVersion(QDataStream::Qt_4_4);
	
	quint32 data;
	streamOut >> data;
	
	qDebug() << "viewer window data" << data;
	
	switch (data)
	{
	case ViewerWindow::NewImage :
		setImage(array);
		break;
	case ViewerWindow::Pixels :
		setPixels(array);
		break;
	case ViewerWindow::Stop :
		clearImage();
		emit closing();
		break;
	}
}


In DataThream function run it reads '2' like I wrote but then whan I pass this class to Plugins dataIn slot it doesnt read QString correctly. qDebug gets "". But when I change a little code for run function like this

Source code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
void DataThread::run()
{
	QDataStream streamOut(socket);
	streamOut.setVersion(QDataStream::Qt_4_4);
	
	quint32 dataType;
	streamOut >> dataType;
	qDebug() << "data thread dataType" << dataType;
	
	QByteArray array;
	array = socket->readAll();
	
	if (dataType == Data::ServerData)
		emit serverData(array);
	if (dataType == Data::PluginData)
		emit pluginData(array);
}


it works, it reads QString and qDebug gets "Program Viewer". But than in ViewerWindow getData the second number isnt '1' but '28' and I do not know why.
Is there something wrong? Cant I read from QByteArray only part of data and then pass it with rest of data to another class? Or is there any other way how to do that?

Thanks for any advice.

Sorry about my english :rolleyes:

2

Sunday, October 5th 2008, 8:00am

Maybe I'm wrong, but each time you "QDataStream streamOut(array);" you just "set QIODevice position to 0". QByteArray is unmodified. Every time you must read/deserialize everything from the start.
imo QDataStream modifies QByteArray only when serializing/writing data.

Source code

1
2
3
//void ProgramViewerMenu::readData(QByteArray array)
// maybe better pass QByteArray as constant reference not a copy?
void ProgramViewerMenu::readData(const QByteArray & array)

readAll function despite the naming do _not_ guarantees that _all_ message bytes will be read at the time. For example. First send (serialized or not) quint32 (or whatever) exact message length information then the message. When reading read quint32 (sizeof quint32) + exact message length bytes and then interpret them.
I mean write a communication protocol.
Sorry for _my_ english ^^
Fighting fire with fire.
Three can keep a secret if two of them are dead.

3

Sunday, October 5th 2008, 4:22pm

I ve tried it but it doesnt work it still reads wrong data. And cant I somehow tell QDataStream where to read?
Thanks for reply.

4

Sunday, October 5th 2008, 5:10pm

Mmm. What have you tried (readAll does not guarante _full_ message passing)? Maybe write simple (maybe without sockets) example? Buildable example would be nice.

Source code

1
2
streamOut << quint32(Data::PluginData) << pluginName << quint32(ProgramViewerMenu::NewImage) << shot.toImage();
// you serialize quint32, QString, quint32, QImage

Source code

1
2
3
void Plugins::dataIn(QByteArray array)
// here you have tried to read the QString at once. But QByteArray is still _not_ modified. Read/deserialize the sequence: quint32, QString, quint32, QImage
// other cases are alike. like in "void ViewerWindow::getData(QByteArray array)"

Consider that reading/deserializing using QDataStream from QByteArray do _not_ modify the (original) QByteArray.
Examine the Fortune Qt example http://doc.trolltech.com/4.4/examples.html#network
Fighting fire with fire.
Three can keep a secret if two of them are dead.

5

Sunday, October 5th 2008, 5:46pm

Yes I understand but I need read one thing in one function and second thing in other function. It is because when I read for example number this number tells me where to pass remaining data. So Is there any way how to read data from QByteArray and take them or remove them. Something like queue. And about readAll. I know that it doesnt guarant that all data is read. This code is only for test. I am going to add the size control but when this wont work it is useless.

6

Monday, October 6th 2008, 7:03am

imho QDataStream is not capable to delete any data. I see two ways. First you can deserialize each time until needed data is reached (in this case serialize small data first). Second you can deserialize everything in one place (say in some slot) and pack data in some structure or class and then use it (or just pass several parameters).
Also you can write a custom >> and << operators for QDataStream and custom class.
Fighting fire with fire.
Three can keep a secret if two of them are dead.