PDA

View Full Version : Can't get this to work... [QTcpSocket]



haggard433
13th September 2010, 20:36
Hi,
I'm trying to create an app for my Symbian phone. It should receive a list with filenames from the Server which is running on my Windows PC, and my phone should put each filename as a new Item in the QWidgetList. The problem is that when my phone receives the filenames it puts some filenames together. E.g:
First Item: Like the way.mp3
Secon Item: Pump it up.mp3blabla.mp3
Third Item: blabla.mp3

I don't know why this happens. I also read the "Fortune Client" Example, but I couldn't really understand it.


void Client::readFortune()
{
/*ui->statusLabel->setText("Connected!");
QDataStream in(tcpSocket);
in.setVersion(QDataStream::Qt_4_0);

char buffer[200] = "";
tcpSocket->read(buffer, tcpSocket->bytesAvailable());
ui->listWidget->addItem(buffer);*/

QDataStream in(tcpSocket);
in.setVersion(QDataStream::Qt_4_0);
QByteArray array1 = tcpSocket->read(100);
ui->listWidget->addItem(array1);

//statusLabel->setText(tr("Connected"));
}

The function is already connected with "readyRead".

JohannesMunk
13th September 2010, 22:45
Hi there!

You need to make use of the tcpSocket->bytesAvailable(). And I think you need to keep track of your packet length, because its not guaranteed to arrive in one piece:

writing:


QByteArray data;
// fill your data...
QDataStream out(tcpSocket);
out << data.size() << data;

reading: You need a member variable in client: int nextBlockSize



void Client::readFortune()
{
QDataStream in(tcpsocket);
in.setVersion(QDataStream::Qt_4_0);
if (nextBlockSize == 0) {
if (tcpsocket->bytesAvailable() < sizeof(int)) return;
in >> nextBlockSize;
}
if ((int)this->bytesAvailable() < nextBlockSize) return;
QByteArray data = tcpsocket->read(nextBlockSize);
// do something with your data..

// Prepare for next block
nextBlockSize = 0;
}

If there is a more elegant solution I would be happy to hear about it - But this one should work!

Joh

PS: I didn't compile the code.. pasted it from an old project and simplified it. there could be some syntax errors :->

wysota
14th September 2010, 01:22
If there is a more elegant solution I would be happy to hear about it - But this one should work!
If all you have to transfer is filenames then you can ignore QDataStream and read the data line by line:

void X::onSocketReadyRead() {
while(socket->canReadLine()){
// you can use QTextStream if you want
// to use stuff such as text codecs
// but here let's read it directly:
QString fileName = socket->readLine();
doSomethingWith(fileName);
}
}

Of course the data needs to be piped into the socket in a similar manner.

Edit: Oh... make sure to have filenames shorter than the TCP window size+socket buffer on your machine or else both presented solutions will fail badly.

JohannesMunk
14th September 2010, 11:18
Hi Wysota!

Yes, thats more elegant for strings!

Is my solution really going to fail for big dataArrays? Wouldn't the system split up / fragment the packet automatically? And my read routine waits till all parts have arrived.

I will have to try or make use of that in the near future. I'll report back.

Of course, if the packet is bigger than the socket buffer, than this fails too. But the default QAbstractSocket (http://doc.trolltech.com/latest/qabstractsocket.html)::readBufferSize() is 0, which corresponds to no limit.

Joh

wysota
14th September 2010, 12:18
Is my solution really going to fail for big dataArrays? Wouldn't the system split up / fragment the packet automatically? And my read routine waits till all parts have arrived.
If you don't read data from the socket, eventually it will fill its buffer and perform network flow control by reducing the TCP window size to 0 thus preventing the transmitting end from sending more data. If the amount of data you expect is not received by then, it never will be.


Of course, if the packet is bigger than the socket buffer, than this fails too. But the default QAbstractSocket (http://doc.trolltech.com/latest/qabstractsocket.html)::readBufferSize() is 0, which corresponds to no limit.
If you don't read data, it will eventually stop flowing -- see for yourself (try sending a 1GB file through a socket and don't start reading it on the receiving end). If that wasn't the case, it would be a perfect denial of service attack opportunity. Unless they changed this behaviour since a couple of releases ago which could be true.

A proper approach would be to read all incoming data into your own buffer and check this buffer for the data you expect. But as I said - maybe they changed something in the socket code.

haggard433
14th September 2010, 13:49
Thanks to both of you, my Phone if finally receiving the songnames! But since I had to "add" \n to the strings which are being sent by the server, my phone makes now a new empty line between the Items in the WidgetList. That isn't the biggest problem. Firstly I should explain what my app for my phone does: The PC (server) sends all filenames to my phone, the phone puts them in a QListWidget and when I double tap on one of them, the phone sends this filename back to the server and the PC then plays this song which is located on PC. It's like a remote control for my PC. But since I had to add the "\n" it also sends the filename with the "\n" back to the server, and the audio library can't play the music file. Is there a way to "take away" the "\n" after the filenames have reached the phone?

wysota
14th September 2010, 13:57
Is there a way to "take away" the "\n" after the filenames have reached the phone?
See QString::trimmed().

haggard433
14th September 2010, 16:05
That was exactly what I was looking for! Thank you very much!:)