Использование QTcpSocket для непрерывного быстрого использования

Мне нужно реализовать клиент, который считывает данные с частотой 300 Гц (300 выборок в секунду). При работе с сокетами C все было в порядке, учитывая тот факт, что мне нужно запускать непрерывный цикл while для получения данных с сервера (который блокирует клиент от обработки чего-либо еще). Итак, я решил попробовать перейти на QTcpsocket, чтобы обрабатывать сигналы, поступающие от другого объекта к клиентскому объекту. Но когда я подключаю Qtcpsocket и подключаю сигнал для чтения

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

это мой куратор -

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

(Я получаю заголовок длиной 12 байт для каждого пакета) Теперь у меня очень медленный клиент - он обрабатывает примерно 3 выборки в секунду ... Я проверил, сколько возвращается bytesavailable(), и похоже, что данные накапливаются. в буфере сокетов. Что я делаю неправильно? Мне нужен очень быстрый клиент, но я не уверен, что способ чтения оптимален. Есть ли более эффективный способ сделать это?

Спасибо


person JLev    schedule 21.06.2017    source источник
comment
Профилируйте свое приложение и посмотрите, где находится узкое место.   -  person John Zwinck    schedule 21.06.2017
comment
На самом деле я использую мини-проект для его тестирования, так что в основном это работает только клиент. Профилирование показывает, что цикл обработки событий занимает много времени, но можно ли этого избежать?   -  person JLev    schedule 21.06.2017
comment
Вы вызываете socket->read(packetLength), не зная, доступны ли packetLength байты. В противном случае следующее чтение будет не синхронизировано с потоком данных.   -  person G.M.    schedule 21.06.2017
comment
Даже если я проверю это с помощью if (socket->bytesAvailable() >= packetLength){ b = socket->read(packetLength); }, ничего не изменится   -  person JLev    schedule 21.06.2017
comment
Когда вы говорите, что цикл обработки событий занимает много времени, можете ли вы сообщить нам конкретное имя функции?   -  person John Zwinck    schedule 21.06.2017
comment
вы можете посмотреть результаты профилирования за 30 секунд чтения здесь: imgur.com/a/8kjUV   -  person JLev    schedule 21.06.2017
comment
Когда вы говорите, что цикл событий занимает много времени, вы понимаете, что ваш обработчик чтения является частью цикла событий? Для дальнейшей диагностики проблемы вам нужно будет больше продемонстрировать свою handleReadyRead реализацию.   -  person G.M.    schedule 21.06.2017
comment
Также обратите внимание, что проверки socket->bytesAvailable() >= packetLength перед чтением недостаточно. Если проверка не удалась, следующий handleReadyRead вызов, вероятно, интерпретирует тело пакета как новый заголовок.   -  person G.M.    schedule 21.06.2017
comment
Это все обработчик- QByteArray b = socket->read(12); int packetLength = (unsigned char)b[6] << CHAR_BIT; packetLength |= (unsigned char)b[7]; if (socket->bytesAvailable() >= packetLength){ b = socket->read(packetLength); }   -  person JLev    schedule 22.06.2017


Ответы (1)


Ваш текущий handleReadyRead предполагает, что полный пакет доступен для чтения и что границы пакета сохранены. TCP так не работает - это просто поток байтов.

Лучшим подходом могло бы быть накопление данных в QByteArray и чтение пакетов из этого QByteArray по мере того, как они становятся доступными.

Итак, если ваш класс client имеет член данных ...

QByteArray m_data;

Я ожидал, что логика будет чем-то вроде ...

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);
}

Вышеупомянутое не проверено, но определенно соответствует строкам кода, которые я использовал в прошлом.

person G.M.    schedule 22.06.2017
comment
Это действительно работает, спасибо. Теперь мне нужно выяснить, почему я получаю пакеты в неправильном порядке .... - person JLev; 22.06.2017