Note that there are some explanatory texts on larger screens.

plurals
  1. POHow to make sure that readyRead() signals from QTcpSocket can't be missed?
    primarykey
    data
    text
    <p>When using <code>QTcpSocket</code> to receive data, the signal to use is <code>readyRead()</code>, which signals that new data is available. However, when you are in the corresponding slot implementation to read the data, no additional <code>readyRead()</code> will be emitted. This may make sense, as you are already in the function, where you are reading all the data that is available. </p> <h2>Problem description</h2> <p>However assume the following implementation of this slot:</p> <pre><code>void readSocketData() { datacounter += socket-&gt;readAll().length(); qDebug() &lt;&lt; datacounter; } </code></pre> <p>What if some data arrives after calling <code>readAll()</code> 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. </p> <h2>One way to minimize the problem (but not avoid it totally)</h2> <p>Of course we can modify the slot like this:</p> <pre><code>void readSocketData() { while(socket-&gt;bytesAvailable()) datacounter += socket-&gt;readAll().length(); qDebug() &lt;&lt; datacounter; } </code></pre> <p>However, we haven't solved the problem. It is still possible that data arrives just after the <code>socket-&gt;bytesAvailable()</code>-check (and even placing the/another check at the absolute end of the function doesn't solve this). </p> <h2>Making sure to be able to reproduce the problem</h2> <p>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:</p> <pre><code>void readSocketData() { datacounter += socket-&gt;readAll().length(); qDebug() &lt;&lt; datacounter; // wait, to make sure that some data arrived QEventLoop loop; QTimer::singleShot(1000, &amp;loop, SLOT(quit())); loop.exec(); } </code></pre> <p>I then let another application send 100,000 bytes of data. This is what happens:</p> <blockquote> <p>new connection!<br> 32768 (or 16K or 48K)</p> </blockquote> <p>The first part of the message is read, but the end isn't read anymore, as <code>readyRead()</code> won't be called again. </p> <p>My question is: what is the best way to be sure, this problem never occurs?</p> <h2>Possible solution</h2> <p>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:</p> <pre><code>void readSocketData(bool selfCall) // default parameter selfCall=false in .h { if (selfCall &amp;&amp; !socket-&gt;bytesAvailable()) return; datacounter += socket-&gt;readAll().length(); qDebug() &lt;&lt; datacounter; QEventLoop loop; QTimer::singleShot(1000, &amp;loop, SLOT(quit())); loop.exec(); QTimer::singleShot(0, this, SLOT(readSocketDataSelfCall())); } void readSocketDataSelfCall() { readSocketData(true); } </code></pre> <p>As I don't call the slot directly, but use <code>QTimer::singleShot()</code>, I assume that the <code>QTcpSocket</code> can't know that I'm calling the slot again, so the problem that <code>readyRead()</code> isn't emitted can't happen anymore. </p> <p>The reason why I have included the parameter <code>bool selfCall</code> is that the slot which is called by the <code>QTcpSocket</code> isn't allowed to exit sooner, else the same problem can occur again, that data arrives exactly at the wrong moment and <code>readyRead()</code> isn't emitted. </p> <p>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?</p>
    singulars
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload