JLev
JLev

Reputation: 705

Using QTcpSocket for continuous fast usage

I need to implement a client that reads data at 300 Hz (300 samples per second). When working with C sockets, everything was ok accept for the fact that I need to run a continuous while loop to get the data from the server (which blocks the client from handling anything else). So, I've decided trying to move to QTcpsocket, in order to handle signals that are coming from other object to the client object. But when I connect the Qtcpsocket, and connect the signal for reading

connect(socket,&QTcpSocket::readyRead, this, &client::handleReadyRead, Qt::ConnectionType::QueuedConnection);

this is my handler -

QByteArray b = socket->read(12);
int packetLength = (unsigned char)b[6] << CHAR_BIT;
packetLength |=  (unsigned char)b[7];
b = socket->read(packetLength);

(I get a 12 byte long header for each packet) Now I get a very slow client - It handles about maybe 3 samples per second...I've checked to see how much bytesavailable() returns, and it looks like data is piling up in the sockets buffer. What am I doing wrong? I have to get a very fast client, but I'm not sure that the way I'm reading is optimal. Is there a more efficient way to do it?

Thank you

Upvotes: 0

Views: 1291

Answers (1)

G.M.
G.M.

Reputation: 12879

Your current handleReadyRead assumes that a complete packet is available to read and that packet boundaries are preserved. TCP doesn't work that way -- it's just a byte stream.

A better approach might be to accumulate data into a QByteArray and read packets from that QByteArray as and when they become available.

So, assuming your client class has a data member...

QByteArray m_data;

I would expect the logic to be something like...

void handleReadyRead ()
{

  /*
   * Append all available data to m_data.
   */
  m_data.append(socket->readAll());

  /*
   * Now work our way through m_data processing complete
   * packets as we find them.  At any given point offset
   * is the total size of all complete packets (including
   * headers) processed thus far.
   */
  int offset = 0;
  while (m_data.length() >= offset + 12) {

    /*
     * We have enough data for a header so read the packet length.
     */
    int packetLength  = (unsigned char)m_data[offset + 6] << CHAR_BIT;
    packetLength     |= (unsigned char)m_data[offset + 7];

    /*
     * Check to see if we have sufficient data for the packet
     * body.  If not then we're done for the time being.
     */
    if (m_data.length() < offset + 12 + packetLength)
      break;

    /*
     * There is enough data for the complete packet so read it.
     * Note that the following will include the header data in the
     * packet variable.  If that's not desired then change it to...
     *
     *   auto packet = m_data.mid(offset + 12, packetLength);
     */
    auto packet = m_data.mid(offset, 12 + packetLength);

    /*
     * Do whatever you want with the packet.
     */
    do_something_with_the_packet(packet);

    /*
     * Update the offset according to the amount of data read.
     */
    offset += 12 + packetLength;
  }

  /*
   * Finally, remove the data processed from the beginning of
   * the QByteArray.
   */
  if (offset)
    m_data = m_data.right(data.size() - offset);
}

The above is untested but is certainly along the lines of code I've used in the past.

Upvotes: 1

Related Questions