Различение тайм-аута соединения и тайм-аута сетевого чтения с помощью Qt / QNetworkAccessManager - PullRequest
0 голосов
/ 06 августа 2020

Я использую QtWebKit (Qt5) (в котором я новичок) для загрузки веб-страниц для проекта, который должен измерять поведение / статус большой коллекции сайтов. Это включает рендеринг этих сайтов, поэтому я выбрал Qt для выполнения этой задачи, поскольку он предоставляет простой интерфейс для рендеринга и захвата изображения со страницы.

Проблема, с которой я столкнулся, заключается в том, что я не могу на всю жизнь из меня выясняют, как различать guish между тайм-аутом соединения и тайм-аутом чтения сокета - в частности тайм-аутом чтения сокета, когда сервер никогда не отправляет ЛЮБЫЕ данные обратно после установления соединения

Итак, два случаи:

  1. Попытка запроса GET на www.filtered.com, межсетевые экраны отбрасывают все пакеты без активного отклонения. Соединение никогда не завершается, срабатывает тайм-аут при блокировке попытки установить sh соединение
  2. Попытка GET-запроса к www.hungbrokenserver.com, соединение завершается почти сразу, но ответ на запрос не возвращается . Тайм-аут происходит при попытке чтения из сокета

Я использую сигналы для обнаружения ошибок. Это позволяет мне фиксировать такие вещи, как отказ в соединении или проблемы с протоколом SSL, среди прочего. Но я не вижу способа определить разницу между тайм-аутом connect() и read() таймаутом, используя QNetworkReply::TimeoutError, поскольку он может срабатывать в любой ситуации и выглядит точно так же

С высокого Перспектива многоуровневого подхода Я понимаю, что есть несколько обходных способов решения проблемы, которые не так просты, как получение сигнала «время ожидания соединения истекло»

Например, если я могу каким-то образом получить сигнал, когда соединение завершается , Я могу пометить флаг как «соединение выполнено успешно», а затем определить позже, когда произойдет тайм-аут, если это произошло из-за соединения или чтения (если я также отмечаю флаг, когда получаю первый байт (ы) от сервера)

Я использую что-то вроде следующего кода - он довольно шаблонный. С его помощью я могу поймать такие вещи, как отказ в соединении, плохой обмен протоколом SSL и даже некоторые сбои уровня 7 (различные коды ответов HTTP считаются ошибками).

   app.connect(page.networkAccessManager(),
              &QNetworkAccessManager::finished,
              &main,
              &MyClass::do_finished);
   ...

   QNetworkReply* reply = manager.get(QNetworkRequest(req));
* 1030 1055 * logi c, чтобы проверить, был ли сигнал результатом ошибки:
MyClass::do_finished(QNetworkReply* r)
{
  g_finished_count++;

  if (!g_finished_count) {
      DEBUG("First network event completed!");
      if (r->error()) {
      DEBUG("First network event finished with an error");
      if (r->error() == QNetworkReply::ConnectionRefusedError) {
          g_connection_refused = true;
          return;
      }

      qDebug() << r->errorString();
      qDebug() << r->readAll();
      switch (r->error()) {
        case QNetworkReply::ConnectionRefusedError:
          DEBUG("Connection refused");
          first_error = NoService;
          break;
        case QNetworkReply::TimeoutError:
            DEBUG("Timeout occurred");
        ...

Я попытался использовать QTimer и использовать функцию QNetworkAccessManager()->connectToHost для обработки соединительной части get() работает сам, но нет возможности сбросить таймер после завершения connectToHost, поэтому поведение точно такое же для отфильтрованной службы и той, которая принимает соединение, но не отправляет данные

Я вижу, что новый метод установки QNetworkAccessManager тайм-аутов был добавлен в Qt 5.15 (QNetworkAccessManager.setTransferTimeout), но мне не ясно, предоставляет ли он механизм для решения проблемы, но, несмотря на это, я не могу принудительно перейти на эту версию на всех моих серверах поскольку кажется, что большинство дистрибутивов не дотягивают до последней версии Qt

, я все еще не могу определить разницу в случаях, потому что для ошибки установлено значение " Операция отменена », вне зависимости от того, была ли она заблокирована в connect() или read() под прикрытием

Так что же мне не хватает? Как я могу определить, является ли тайм-аут результатом тайм-аута соединения или результатом успешного соединения, которое истекло в ожидании данных от сервера? Я почти уверен, что нет никаких сигналов, специально предназначенных для этой цели, но, возможно, есть обходной путь, который я не вижу?

Примечание: я понимаю, что могу использовать отдельное базовое c TCP-соединение, прежде чем выполнять HTTP-запрос, но это не совсем элегантное решение и требует дополнительного подключения. Похоже, в этом нет необходимости ...

...