Я использую QtWebKit (Qt5) (в котором я новичок) для загрузки веб-страниц для проекта, который должен измерять поведение / статус большой коллекции сайтов. Это включает рендеринг этих сайтов, поэтому я выбрал Qt для выполнения этой задачи, поскольку он предоставляет простой интерфейс для рендеринга и захвата изображения со страницы.
Проблема, с которой я столкнулся, заключается в том, что я не могу на всю жизнь из меня выясняют, как различать guish между тайм-аутом соединения и тайм-аутом чтения сокета - в частности тайм-аутом чтения сокета, когда сервер никогда не отправляет ЛЮБЫЕ данные обратно после установления соединения
Итак, два случаи:
- Попытка запроса GET на www.filtered.com, межсетевые экраны отбрасывают все пакеты без активного отклонения. Соединение никогда не завершается, срабатывает тайм-аут при блокировке попытки установить sh соединение
- Попытка 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-запрос, но это не совсем элегантное решение и требует дополнительного подключения. Похоже, в этом нет необходимости ...