[SOLVED] reading data in QTCPsocket is incomplete
-
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
-
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.
-
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
-
-
[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.
-
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
-
@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 -
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();
}
}@ -
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. -
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
-
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 !