Russian Qt Forum

Qt => Работа с сетью => Тема начата: Aso Renji от Май 12, 2012, 01:26



Название: Запрос HTTP заголовков
Отправлено: Aso Renji от Май 12, 2012, 01:26
Стоит задача получить заголовки страницы. В крайнем случае получить информацию о том, что вместо заголовков сервер присылает фигу. Для этого создается QNetworkAccessManager, у которого пинается head. Потом программа ловит сигнал finished от QNetworkAccessManager и сигнал error от QNetworkReply. Так вот, при попытке обратиться к http://www.miracle-train.tv/ ни один из слотов вообще не вызывается (да, error тоже не ловится). Хотя, если стучаться на какой ни будь там http://ya.ru/ - все нормально. Что делать и кто виноват?

И, собственно, тестовый код максимально урезанный для локализации глюка:
Код:
class browser:public QObject
{
    Q_OBJECT
public:
    browser(QObject*parent):QObject(parent),NAM(this)
    {
        QObject::connect(&NAM,SIGNAL(finished(QNetworkReply*)),this,SLOT(loadFinished(QNetworkReply*)));
        QNetworkRequest request(QUrl("http://www.miracle-train.tv/"));
        QNetworkReply*reply=NAM.head(request);
        QObject::connect(reply,SIGNAL(error(QNetworkReply::NetworkError)),this,SLOT(error(QNetworkReply::NetworkError)));
    }
private:
    QNetworkAccessManager NAM;
private slots:
    void error(QNetworkReply::NetworkError code)
    {
        qDebug()<<"error";
    }
    void loadFinished(QNetworkReply*reply)
    {
        qDebug()<<"ok";
        reply->deleteLater();
    }
};
Выполняется под Дебианом, который в свою очередь работает под VirtualBox. Остальные приложения работающие с сетью в глюках незамечены.


Название: Re: Запрос HTTP заголовков
Отправлено: fuCtor от Май 12, 2012, 06:34
Проблема в сервере, на запрос HEAD он тупо ничего не отдает и просто висит. Проверил через Fiddler под Windows.


Название: Re: Запрос HTTP заголовков
Отправлено: Aso Renji от Май 12, 2012, 13:28
Ок, что тогда в этой ситуации делать? Убивать зависшее соединение руками несколько неудобно. Где выставить таймаут для ожидания ответа сервера я тоже не нашел. А если соединение предоставить само себе, оно так и висит до бесконечности в ожидании ответа сервера, который никогда не будет отправлен.


Название: Re: Запрос HTTP заголовков
Отправлено: SimpleSunny от Май 13, 2012, 13:40
Создайте таймер.
На сигнал timeout() reply->abort(); и прийдет сигнал error.
Если запрос закончился раньше, то останавливайте его.
Еще на readyRead() можно поставить restart таймера.


Название: Re: Запрос HTTP заголовков
Отправлено: Aso Renji от Май 13, 2012, 14:27
Тогда следующий вопрос - можно ли как-то скрестить таймер и QNetworkReply, на случай если соединений больше одного и каждому свой таймер нужен? Я уже пробовал создавать наследника QNetworkAccessManager, перегружать в нем createRequest и возвращать потомка QNetworkReply с таймером. Но выяснил что в QNetworkReply не реализован abort (он pure virtual). А делать таймер отдельным объектом, это все же некоторый дополнительный геморрой. Хотя и не смертельный.


Название: Re: Запрос HTTP заголовков
Отправлено: fuCtor от Май 20, 2012, 08:33
Если соединений много, то имеет смысл сделать такую схему:
1) завести один таймер и выставить в нем интервал в 1с.
2) т.к. QNetworkReply потомок QObject, то в нем можно хранить динамические свойства => помещаем в него свойство, которое назовем условно TTL.
3) если нужно централизовать все это то наследуемся от QNetworkAccessManager и храним этот таймер там.
4) при создании запроса, запоминаем где-то QNetworkReply, лучше через связку QPointer< QNetworkReply >, и инициализируем наше динамическое свойство, например выставляем в 5с
5) при срабатывании таймера пробегаем по всем сохраненным объектам и уменьшаем TTL (если есть) на единицу, если TTL = 0, то убиваем его ( вызываем close() )
6) если список пуст, таймер можно остановить, при появлении новых запросов запустить снова.
7) если ответ получить, свойство TTL лучше удалить (присвоив ему QVariant()) во избежание удаления по таймеру.

для надежности можно прицепить с сигналу destroyed слот, чтобы удаленный объект убрать из списка.