How to make sure that readyRead() signals from QTcpSocket can't be missed? - c++

When using QTcpSocket to receive data, the signal to use is readyRead(), which signals that new data is available.
However, when you are in the corresponding slot implementation to read the data, no additional readyRead() will be emitted.
This may make sense, as you are already in the function, where you are reading all the data that is available.
Problem description
However assume the following implementation of this slot:
void readSocketData()
{
datacounter += socket->readAll().length();
qDebug() << datacounter;
}
What if some data arrives after calling readAll() but before leaving the slot?
What if this was the last data packet sent by the other application (or at least the last one for some time)?
No additional signal will be emitted, so you have to make sure to read all the data yourself.
One way to minimize the problem (but not avoid it totally)
Of course we can modify the slot like this:
void readSocketData()
{
while(socket->bytesAvailable())
datacounter += socket->readAll().length();
qDebug() << datacounter;
}
However, we haven't solved the problem. It is still possible that data arrives just after the socket->bytesAvailable()-check (and even placing the/another check at the absolute end of the function doesn't solve this).
Making sure to be able to reproduce the problem
As this problem of course happens very rarely, I stick to the first implementation of the slot, and I'll even add a an artificial timeout, to be sure that the problem occurs:
void readSocketData()
{
datacounter += socket->readAll().length();
qDebug() << datacounter;
// wait, to make sure that some data arrived
QEventLoop loop;
QTimer::singleShot(1000, &loop, SLOT(quit()));
loop.exec();
}
I then let another application send 100,000 bytes of data.
This is what happens:
new connection!
32768 (or 16K or 48K)
The first part of the message is read, but the end isn't read anymore, as readyRead() won't be called again.
My question is: what is the best way to be sure, this problem never occurs?
Possible solution
One solution I came up with is calling the same slot again at the end again, and to check at the beginning of the slot, if there is any more data to read:
void readSocketData(bool selfCall) // default parameter selfCall=false in .h
{
if (selfCall && !socket->bytesAvailable())
return;
datacounter += socket->readAll().length();
qDebug() << datacounter;
QEventLoop loop;
QTimer::singleShot(1000, &loop, SLOT(quit()));
loop.exec();
QTimer::singleShot(0, this, SLOT(readSocketDataSelfCall()));
}
void readSocketDataSelfCall()
{
readSocketData(true);
}
As I don't call the slot directly, but use QTimer::singleShot(), I assume that the QTcpSocket can't know that I'm calling the slot again, so the problem that readyRead() isn't emitted can't happen anymore.
The reason why I have included the parameter bool selfCall is that the slot which is called by the QTcpSocket isn't allowed to exit sooner, else the same problem can occur again, that data arrives exactly at the wrong moment and readyRead() isn't emitted.
Is this really the best solution to solve my problem?
Is the existence of this problem a design error in Qt or am I missing something?

Short answer
The documentation of QIODevice::readyRead() states:
readyRead() is not emitted recursively; if you reenter the event loop or call waitForReadyRead() inside a slot connected to the readyRead() signal, the signal will not be reemitted.
Thus, make sure that you
don't instantiate a QEventLoop inside your slot,
don't call QApplication::processEvents() inside your slot,
don't call QIODevice::waitForReadyRead() inside your slot,
don't use the same QTcpSocket instance within different threads.
Now you should always receive all data sent by the other side.
Background
The readyRead() signal is emitted by QAbstractSocketPrivate::emitReadyRead() as follows:
// Only emit readyRead() when not recursing.
if (!emittedReadyRead && channel == currentReadChannel) {
QScopedValueRollback<bool> r(emittedReadyRead);
emittedReadyRead = true;
emit q->readyRead();
}
The emittedReadyRead variable is rolled back to false as soon as the if block goes out of scope (done by the QScopedValueRollback). So the only chance to miss a readyRead() signal is when the control flow reaches the if condition again before the processing of the last readyRead() signal has finished (in other words, when there would be a recursion).
And a recursion should only be possible in the situations listed above.

I think scenario mentioned in this topic has two major cases which works differently, but in general QT doesn't have this problem at all and I will try to explain below why.
First case: Single threaded application.
Qt uses select() system call to poll open file descriptor for any change happened or operations available. Simple saying on every loop Qt checks if any of opened file descriptors have data available to read/closed etc. So on single threaded application flow looks like that (code part simplified)
int mainLoop(...) {
select(...);
foreach( descriptor which has new data available ) {
find appropriate handler
emit readyRead;
}
}
void slotReadyRead() {
some code;
}
So what will happend if new data arrived while program still inside slotReadyRead.. honestly nothing special. OS will buffer data, and as soon as control will return to next execute of select() OS will notify software that there are data available for particular file handle. It works in absolutely the same way for TCP sockets/files etc.
I can imaging situations where (in case of really long delays in slotReadyRead and a lot of data coming) you can experience an overrun within OS FIFO buffers (for example for serial ports) but that has more to do with a bad software design rather then QT or OS problems.
You should look on slots like readyRead like on a interrupt handlers and keep their logic only within fetch functionality which fills your internals buffers while processing should be done in separate threads or while application on idle etc.. Reason is that any such application in general is a mass service system and if it spends more time on serving one request then a time interval between two requests it's queue will overrun anyway.
Second scenario: multithreaded application
Actually this scenario is not that much differ from 1) expect that you should design right what happens in each of your threads. If you keep main loop with light wighted 'pseudo interrupt handlers' you will be absolutely fine and keep processing logic in other threads, but this logic should work with your own prefetch buffers rather then with QIODevice.

The problem is quite interesting.
In my program the usage of QTcpSocket is very intensive. So I've written the whole library, that breaks outgoing data into packages with a header, data identifier, package index number and maximum size, and when the next piece of data comes, I know exactly where it belongs to. Even if I miss something, when the next readyRead comes, the receiver reads all and compose received data correctly. If the communication between your programs is not so intense, you could do the same, but with timer (which is not very fast, but solves the problem.)
About your solution. I don't think it's better then this:
void readSocketData()
{
while(socket->bytesAvailable())
{
datacounter += socket->readAll().length();
qDebug() << datacounter;
QEventLoop loop;
QTimer::singleShot(1000, &loop, SLOT(quit()));
loop.exec();
}
}
The problem of both methods is the code right after leaving the slot, but before returning from emitting the signal.
Also you could connect with Qt::QueuedConnection.

Here are some examples of ways to get the whole file, but using some other parts of the QNetwork API:
http://qt-project.org/doc/qt-4.8/network-downloadmanager.html
http://qt-project.org/doc/qt-4.8/network-download.html
These examples show a stronger way to handle the TCP data, and when buffers are full, and better error handling with a higher level api.
If you still want to use the lower level api, here is a post with a great way to handle the buffers:
Inside your readSocketData() do something like this:
if (bytesAvailable() < 256)
return;
QByteArray data = read(256);
http://www.qtcentre.org/threads/11494-QTcpSocket-readyRead-and-buffer-size
EDIT: Additional examples of how to interact with QTCPSockets:
http://qt-project.org/doc/qt-4.8/network-fortuneserver.html
http://qt-project.org/doc/qt-4.8/network-fortuneclient.html
http://qt-project.org/doc/qt-4.8/network-blockingfortuneclient.html
Hope that helps.

If a QProgressDialog shall be shown while receiving data from a socket it only works if any QApplication::processEvents() are sent (e.g. by the QProgessDialog::setValue(int) methode). This of course leads to the loss of readyRead signals as mentioned above.
So my workaround was a while loop including the processEvents command such as:
void slot_readSocketData() {
while (m_pSocket->bytesAvailable()) {
m_sReceived.append(m_pSocket->readAll());
m_pProgessDialog->setValue(++m_iCnt);
}//while
}//slot_readSocketData
If the slot is called once any additional readyRead signals can be ignored because the bytesAvailable() always returns the actual number after the processEvents call. Only on pausing of the stream the while loop ends. But then the next readReady is not missed and starts it again.

I had the same problem right away with the readyRead slot. I disagree with the accepted answer; it doesn't solve the problem. Using bytesAvailable as Amartel described was the only reliable solution I found. Qt::QueuedConnection had no effect. In the following example, I'm deserializing a custom type, so it's easy to predict a minimum byte size. It never misses data.
void MyFunExample::readyRead()
{
bool done = false;
while (!done)
{
in_.startTransaction();
DataLinkListStruct st;
in_ >> st;
if (!in_.commitTransaction())
qDebug() << "Failed to commit transaction.";
switch (st.type)
{
case DataLinkXmitType::Matrix:
for ( int i=0;i<st.numLists;++i)
{
for ( auto it=st.data[i].begin();it!=st.data[i].end();++it )
{
qDebug() << (*it).toString();
}
}
break;
case DataLinkXmitType::SingleValue:
qDebug() << st.value.toString();
break;
case DataLinkXmitType::Map:
for (auto it=st.mapData.begin();it!=st.mapData.end();++it)
{
qDebug() << it.key() << " == " << it.value().toString();
}
break;
}
if ( client_->QIODevice::bytesAvailable() < sizeof(DataLinkListStruct) )
done = true;
}
}

i got the same problem, rather use signal readyRead() and socket.readall, i' m trying the following, just after connect without be sure :
QByteArray RBuff;
if(m_socket->waitForConnected(3000))
{
while (m_socket->ConnectedState == QAbstractSocket::ConnectedState) {
RBuff = m_socket->read(2048);
SocketRead.append(RBuff);
if (!SocketRead.isEmpty() && SocketRead.length() == 2048)
{
readData(SocketRead);
SocketRead.remove(0,2048);
}
QCoreApplication::processEvents(QEventLoop::AllEvents, 100);
}
//m_socket->close();*/
}
else
{

Related

Qt: is there any way to call a sequence of slots with certain time interval?

The way I am working now is to connect a QTimer to the first slot, inside the first slot it will trigger another single-shot QTimer which will trigger the second slot... and so on.
If I update all of the widgets at once, the GUI will stuck for a flash of a second. But it is noticeable. So I want to avoid that.
But this is very difficult to write code. You have to add QTimer everywhere. Are there any better solutions?
EDIT: This is how I update my widget, maybe there is better way?
void UAVInfoView::updateDisplay()
{
if (!visibleRegion().isEmpty()){
info = _dataSrc->getUAVInfo(_id-1);
if (info)
{
//if new package received try to do updating.
if (_pakchk != info->_pakcnt){
//only update the text if there is communication
if (info->_communication != COMMSTATUS::WAIT4CONNECTION && info->_communication != COMMSTATUS::LOST)
{
ui->plainTextEdit->setPlainText(tr("x: %1\ny: %2\nz: %3").arg(info->_pos[0]).arg(info->_pos[1]).arg(info->_pos[2]));
}
//only update the status indicator only if status changed.
if (_status != info->_communication)
{
switch (info->_communication){
case COMMSTATUS::CONNECTED:
ui->groupBox->setStyleSheet("QGroupBox#groupBox {background-color:green;}");
ui->label_2->setText("On Line");
break;
case COMMSTATUS::LOST:
ui->groupBox->setStyleSheet("QGroupBox#groupBox {background-color:red;}");
ui->label_2->setText("Lost");
break;
case COMMSTATUS::WAIT4CONNECTION:
ui->groupBox->setStyleSheet("QGroupBox#groupBox {background-color:grey;}");
ui->label_2->setText("Off Line");
}
}
}
//update the status and package counter to serve the state machine.
_status = info->_communication;
_pakchk = info->_pakcnt;
}
}
}
As you can see, it is just a bunch of default =, ! if else things...
You can call them in a slot connected to a timer with a certain interval. Your slot that is connected to the timer could be like :
void myClass::onTriggered()
{
switch(turn){
case 0:
slot1();
break;
case 1:
slot2();
break;
...
}
turn++;
if(turn>=numberOfSlots)
turn = 0;
}
This way each time one slot is called and they are called sequentially.
I'm not quite sure what you try to achieve, but if you want to trigger the execution of a specific set of functions with a timer, you probably have to introduce some controlling instance with a singe QTimer that you can use as often as you like.
Now that you said you don't want to update all your GUI widgets all the time, and I guess you are using QWidgets, you could also use the setUpdatesEnabled(bool) method to disable all effects of update() or repaint() calls.
If this doesn't help you, maybe you can explain you problem a bit more detailed?
Although I believe the problem is somewhere else, I'll give you one possible solution. You could use a state machine. Just have one slot that is triggered by your timer in which you call some other functions based on the current state.
...
connect(&timer, SIGNAL(timeout()), this, SLOT(myStateSlot()));
timer.start(1000);
...
void MyClass::myStateSlot()
{
switch(state)
{
case State_Start:
operation1();
// you can change the state here.. or somewhere else.. up to your design
break;
case State_Two:
operation2();
break;
case State_End:
timer.stop();
break;
}
}
Your problems likely stem from the relative slowness of the QPlainTextEdit. Use a QLabel instead. Otherwise, the code looks fine. Make sure that if there are multiple consequent calls to updateDisplay, they should all happen without the control returning to the event loop between the calls.
The below is wrong, since each processEvents forces a repaint of the widgets.
w.updateDisplay();
QCoreApplication::processEvents();
w.updateDisplay();
QCoreApplication::processEvents();
You might be invoking processEvents() without realizing it. It is effectively invoked every time you return from QObject::event() and the event queue is empty at the time. Also note that QObject::event() is the caller of queued slot calls. Thus, if you have a queued connection to a slot, the control returns to the event loop right after the slot returns.
If the update method is complex, you should try QtConcurrent::map() to run the update in another thread. Then you need no delay, because you'll get notified from map() when the updates are finished.

What's the quickest way to return the contents of a webpage in Qt?

so, I'm trying to run some simple code in Qt to return the contents of a given web page. After doing quick research, I was able to develop my own class to simplify the process:
WebFetch::WebFetch()
{
nam = new QNetworkAccessManager(this);
connect(nam, SIGNAL(finished(QNetworkReply*)), this, SLOT(finished(QNetworkReply*)));
}
QString WebFetch::get(QString url)
{
nam->get(QNetworkRequest(QUrl(url)));
}
void WebFetch::finished(QNetworkReply* reply)
{
QByteArray data = reply->readAll();
QString str(data);
}
However, there big problem that I'm finding with the above code is that the call is asynchronous. I would like the "get" function to simply return the string after it is retrieved, which seems impossible on the account that it needs to wait for the finished signal, at which point there's no way of having "get" return whatever content is retrieved by the "finished" slot. Is there any alternative to the above method or is there a way I can get "get" to return the content retrieved by "finished"? Any help would be greatly appreciated. Thanks!
The call being asynchronous is not a problem - it's a big win. With a synchronous call, you're essentially wasting potentially hundreds ok KB of RAM, and an entire thread, just idly waiting for something to come back. You can't write such code while pretending that things happen synchronously or even "quickly" for that matter. I won't even comment on the insanity of running such synchronous code in the GUI thread. It's also a very bad idea to run a local event loop, since suddenly all of your GUI code becomes reentrant. My bet is that you neither design nor test for that.
You have to break down whatever code is expecting the result into two parts: the first part needs to place the request. The second part, in a slot, is notified when the request is finished and continues doing whatever is to be done.
If you wish to have it all in a single method, use C++11:
QNetworkAccessManager * mgr = ...;
QObject::connect(mgr, &QNetworkAccessManager::finished,
[this, mgr](QNetworkReply * reply){
// here you can do things with the reply
});
mgr->get(QNetworkRequest("....");
For a complete example, see this 300-line photographic mosaic generator that pulls random images from imgur. It extensively uses asynchronous, multithreaded processing and lambdas in the above style.

signal prior QThread event loop start is lost

I have a case where a signal is being lost and I don't understand why -- normally signals sent prior to the event loop starting just get queued up and sent then.
This is what the code looks like (for a QThread object):
void OffloadHandler::run()
{
cout << "Start" << endl;
connect( this, SIGNAL(loopStarted()), SLOT(onLoopStarted()), Qt::QueuedConnection );
emit loopStarted();
exec();
}
void OffloadHandler::onLoopStarted()
{
cout << "Here!" << endl;
}
The thread is started elsewhere and Start is written to the console but Here1 never is -- the signal is not received. I use the same pattern in my main message loop and it works, but in this threaded message loop it appears not to work.
Is there anything clearly wrong in my code here?
Your code is valid and it should run. Are you sure you have an event loop running in the thread that oh is created in?
Cause the emit loopStarted() should send an event to oh's event loop, which will be processed and will call onLoopStarted(). I've tested your code out, and it works for me.
Btw, It's generally recommended that you do not add slots to your QThread, and avoid using moveToThread( this );
Unfortunately, I don't really understand your use case, so I can't give a better solution. But here is some amazing documentation which has nice DOs and DONTs regarding QThreads.
Okay, I've figured it out, I've been bitten by the QThread ownership oddity. One has to be really careful when connecting to the QThread object itself since that Object is not owned by the thread by default.
So at the point where the thread is created I must move the thread to the thread:
OffloadHandler * oh = new OffloadHandler();
oh->moveToThread( oh ); //MOVE TO SELF!
oh->start();
Once I do this the signals work as expected.

Optimizing QPlainTextEdit Widget When Bombarded with Data?

So basically what I have is a Qt application that has a main GUI thread and a worker thread.
The worker thread is something like this:
void Client::readResults(int msgqid, pid_t pid)
{
int ret;
msg_t message;
connect(this, SIGNAL(dataReceived(QString)), this, SLOT(updateDisplay(QString)));
connect(this, SIGNAL(doneProcessing(QString)), this, SLOT(updateStatus(QString)));
for (;;)
{
ret = msgrcv(msgqid, &message, MSGSIZE, pid, 0);
if (ret == -1)
{
showStatusBarError("msgrcv");
return;
}
if (ret > 0)
{
emit dataReceived(QLatin1String(message.info));
if (message.is_eof)
{
emit doneProcessing("Done!");
break;
}
}
}
}
All it does is it reads from a message queue and emits a signal that causes a QPlainTextEdit widget from the main GUI thread (that spawned this thread) to call appendPlainText(message.info) so that the data received from the message queue is appended to the widget.
The problem is if I'm reading huge chunks of data from the queue (it's actually a text file around 30MB or more), the whole GUI just hangs until the worker thread finishes. Is there a way to make it not hang and for the user to actually see the QPlainTextEdit widget scrolling as it received data from the worker thread?
Thanks!
I had a similar problem before. In my case, and from my experience, the Signal/Slot System seems to lock the program flow. When you read in a lot of data or frequently read in some data it will naturally cause the GUI to slow down.
What worked for me was to use model-based input, which allows a steady and smooth update.
You might want to consider relocating the input so that you can directly read from the input to the GUI?

Problems with reading data from QTcpSocket

I've modified the threaded fortune-server from Qt examples.
The client connects to the server and then sends a header to authenticate.
tcpSocket = new QTcpSocket();
tcpSocket->connectToHost(addr, port);
QByteArray block = "someheader";
int x = tcpSocket->write(block);
qDebug() << x;
The client seems OK here and qDebug prints the actual size of block.
On the server side I've predefined incomingConnection and I start thread to each new connection.
void Server::incomingConnection(int socketDescriptor) {
const QString &str = vec[qrand() % vec.size()];
SpellThread *thread = new SpellThread(socketDescriptor, str);
connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));
qDebug() << " -- incoming connection";
thread->start();
}
I'm connecting sock to check is there something to read. (sock here is QTcpServer*)
void SpellThread::run() {
qDebug() << " -- in spellthread";
connect(sock, SIGNAL(readyRead()), this, SLOT(checkBytes()));
//....
qDebug() << " -- end spellthread";
}
The first problem is that when I'm sending data from the client, readyRead is not fired. (I've added debug message in checkBytes)
Messages are:
-- incoming connection
-- in spellthread
-- end spellthread
Although the client prints the actual size of header length.
The second problem is that checkBytes currently is very bad-designed. First it checks is header OK and sets a flag, then it gets the size of message and sets another flag and finally it gets the real message. This is very clumsy. I first tried to escape signals and instead use sock->waitForReadyRead(). However it always returns false. (From the docs: "Reimplement this function to provide a blocking API for a custom device. The default implementation does nothing, and returns false.").
So how to really make a client/server application in Qt with multiple clients and multiple reads/writes? I really want suggestions to improve design of my application and to solve my current two problems.
You can't use slots or socket signals with a thread without calling QThread::exec() to start an event loop within that thread/the run function.
Since your checkBytes slot belongs to QThread, it wouldn't be executed by the thread (there is a detailed article about QThreads here)
The closest example that seems to already do what you want is the Network Chat (particularly the two classes Server and Connection).
----------Edit
If you need to use threads (without any slot), the QTcpSocket object must belongs to the same thread as the one where you call waitForReadyRead. For example, with:
SpellThread::SpellThread(int socketDescriptor, const QString & str) {
tcpSocket = new QTcpSocket(); // There should be no parent to be able
// to move it to the thread
tcpSocket->moveToThread(this);
...
Or by creating the QTcpSocket object inside the run function so that it automatically belongs to that thread (it was briefly explained in the fortune example).
If you allocate the QTcpSocket dynamically, and because it won't have a parent, you should also delete it manually.