[SOLVED] reading data in QTCPsocket is incomplete
-
wrote on 19 Feb 2014, 18:06 last edited by
hi !
i am trying to have my data read correctly over TCP for days and i can't make it work !
i send a command like "COP01" and i am supposed to get this a s a response :
@COP01
~MSG~My message
@CV@but i get only
@COP01@
I am using readyRead() signal along with a slot where i do a simple
@qDebug() << socket->readAll();@
Note : when i use telnet in a terminal and send the command manually, i get the right answer.
I also tried some mixed solutions like using .atEnd(), canReadLine() and other tricks i grabbed on internet and had a look on Fortune example from Qt... but with no success at all !
can you tell me how you manage reading messages over TCP ?
Thank you very much
-
wrote on 20 Feb 2014, 05:06 last edited by
That is because your message sended not as one TCP packet but several. Ready read called when received any new packet. For solving this issue you need implement some kind of top level protocol where you know start of message and when you got complete data. For example you can use json like structure where you know start and end, or use some start identifier and length of data. All depends from your requirements.
-
wrote on 20 Feb 2014, 06:13 last edited by
Hello Marty,
When you write your data on socket you use socket->write() function.
It returns no of bytes written to a socket if your data is written completely then there is no problem on writing side.
Check it out using qDebug(). -
wrote on 20 Feb 2014, 11:16 last edited by
Hi and thank you for your suggestions !
the thing is :
-
the server is a device and i don't have much information about the TCP message format for the answer. The only thing i know is the response message is composed of :
-
the command the device received + EOL (CR/LF)
-
the answer to the query, here this is the message stored in memory + EOL (CR/LF)
-
state of execution (valid or not) + EOL (CR/LF)
it would be great if the device sends the message size in the TCP frame but i don't have this information.
So i don't know how to be sure i read all data !
I will try to get the number of bytes written to the device as suggested.
Could the EOL (CR/LF) be a problem when reveiving TCP packets ?
How can i handle this ?thanks a lot
-
-
wrote on 20 Feb 2014, 11:39 last edited by
[quote author="Marty" date="1392894981"]
- the command the device received + EOL (CR/LF)
- the answer to the query, here this is the message stored in memory + EOL (CR/LF)
- state of execution (valid or not) + EOL (CR/LF)
[/quote]
You already have enough information. Just wait until you receive all three parts of message which are ends with EOL.
-
wrote on 20 Feb 2014, 11:45 last edited by
how would you write this part ?
because in the documentation it says the response always ends with "@ + first letter of the command sent + state (like V for valid or E for error) + EOL".
I tried to detect the character "@" yesterday just for a test purpose but my app froze like in infinite loop while waiting for that character that never arrives.Also, why when i send the command with telnet in a terminal i get the entire answer. How does telnet know when it gets the entire response ?
thanks again
-
wrote on 20 Feb 2014, 11:46 last edited by
@OK your server is a device ,the information you only know the composition of message as response from the server .
Your problem is you are not getting full data from the server(Which is unknown to you) .
You can use QQueue data structure -QQueue <QByteArray>Queue; (in .h file)
QBytearray data=pSocket->readAll();
qDebug() << "Data From Client : " << "\n\n" <<data;
Queue.enqueue(data);while(!Queue.isEmpty())
{
QString str=Queue.dequeue();
QString str=data;qdebug() << str ; str.clear();
}
try it -
wrote on 20 Feb 2014, 12:42 last edited by
Use Wireshark, so you can see what exactly happening(what data sends by device) in network.
And as IamSumit wrote using QQueue is good solution. -
wrote on 20 Feb 2014, 12:51 last edited by
By the way
can you show code how do you doing it? -
wrote on 20 Feb 2014, 13:26 last edited by
yep. will have a look to QQueue.
here is some code.
When i clic a button :
@void ledBar::getStoredMessage(int bank)
{
QString message;
if (bank < 10)
{
message = sendQuery("COP0" + QString::number(bank) + "\r\n");
}
else
{
message = sendQuery("COP" + QString::number(bank) + "\r\n");
}
qDebug() << message;
}@The sendQuery() Method :
@void TCPClient::sendQuery(QByteArray query)
{
if (socket->state() != QAbstractSocket::ConnectedState)
{
qWarning() << "Can't send command : not connected !";
}
else
{
socket->write(query)
}
}
@then my readYread() slot :
@void TCPClient::readyRead()
{
if(socket->waitForBytesWritten(2000) && socket->waitForReadyRead((2000)))
{
timer->start(timeout);
return socket->readAll();
}
}@ -
wrote on 21 Feb 2014, 07:01 last edited by
Is your code compiled ok?
Anyway, let's change your code in following way:
Add some buffer variables in your class
@private:
//....
QString responseTempalte;
QByteArray incommingData;
bool isDataComplete;
//....@
change getStoredMessage(int bank)
@void ledBar::getStoredMessage(int bank)
{
QString message = QStringLiteral("COP%1\r\n").arg(bank, 2, 10, QChar('0'));
responseTempalte = QStringLiteral("@%1%2\r\n").arg(message.at(0));
incommingData.clear();
isDataComplete = false;
sendQuery(message.toLatin1());
qDebug() << message;
}@
and most important part, readyRead slot
@void TCPClient::readyRead()
{
incommingData.append(socket->readAll());
if(incommingData.contains(responseTempalte.arg("V")) ||
incommingData.contains(responseTempalte.arg("E")) )
{
isDataComplete = true;//or emit some signal
}
}@
something like that, i hope didn't forget something important. -
wrote on 21 Feb 2014, 07:06 last edited by
Great i will give it a try !
maybe the best is, if you have time, to have a look at the whole project :
https://github.com/martialgallorini/ledManager
thanks a lot
-
wrote on 21 Feb 2014, 14:29 last edited by
humm... can't make it to work
program without change compile and run well (except truncated TCP response)
i have applied the changes you suggested. It compiles ok, but when clic on send command button it freezes then close then crashes the app
-
wrote on 23 Feb 2014, 09:11 last edited by
Well i figured it out but i don't understand why !
With
[CODE]socket->readLine();[/CODE]
it reads each complete line.
I tried everything (read(), readAll()...) and NOTHING but readLine() works !
If anybody has a clue why readAll() does'nt make it here...[CODE]
void TCPClient::readyRead()
{
if(socket->waitForReadyRead(2000))
{
QString resp;
while(socket->bytesAvailable() > 0)
{
resp.append(socket->readLine());
}
emit sigTcpDataReceived(resp.toUtf8());
}
else
{
qWarning() << "Waiting for data to read timed out. No data received !";
}
}
[/CODE]Thank you very much to everybody and for your help !
1/14