Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > C++ Builder > Убрать кеширование запросов в интернет


Автор: Bima 18.12.2006, 08:57
Делаю программу, которая проверяет размер файла из интернета, но заметил странную особенность. Если запустить программу и сразу запросить размер файла, то мне программа ВСЕГДА выдает размер 2379, но стоит хоть раз скачать этот файл, то программа выдает истинный размер файла. Пробовал на многих файлах из интернета, всегда одно и тоже. Такое ощущение, что запрос где то кешируется и если в кеше нет информации о файле, то запрос возвращает любое число.

Код программы:
Код

//---------------------------------------------------------------------------
#include <memory>
#include <vcl.h>
#include <urlmon.h>
#pragma comment(lib,"urlmon.lib")
#include <wininet.h>
#pragma comment(lib,"wininet.lib")

#include "Kod.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
__int64 GetInetFileSize(char *url);
AnsiString myUrl;
AnsiString MyFile;
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner):TForm(Owner){}
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
int retcode;
retcode = URLDownloadToFile( NULL, myUrl.c_str(), MyFile.c_str(), 0, 0 );
Label1->Caption=IntToStr(retcode);
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Button2Click(TObject *Sender)
{
myUrl="http://www.biminc.narod.ru/Test.zip";
MyFile="c:\\Test.zip";
__int64 a;
a=GetInetFileSize(myUrl.c_str() );
Label1->Caption=IntToStr(a);
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Button3Click(TObject *Sender)
{
myUrl="http://www.drweb.ru/bases/dwrtoday.zip";
MyFile="c:\\dwrtoday.zip";
__int64 a;
a=GetInetFileSize(myUrl.c_str());
Label1->Caption=IntToStr(a);
}
//---------------------------------------------------------------------------
__int64 GetInetFileSize(char *url)
{
HINTERNET hInet, hUrl;
char nSize[32];
__int64 Size;
DWORD nBuffLen;

hInet = InternetOpen("YOUR_AGENT",//"Microsoft Internet Explorer",
                     NULL,
                     NULL,
                     NULL,
                     NULL);
if (hInet != NULL)
   {
   Form1->Label3->Caption=IntToStr(Integer(hInet));  //ShowMessage("hInet="+IntToStr(Integer(hInet)));
   hUrl = InternetOpenUrl(hInet,
                          url,
                          NULL,
                          NULL,
                          NULL,
                          NULL);
   Form1->Label5->Caption=IntToStr(Integer(hUrl));//ShowMessage("hUrl="+IntToStr(Integer(hUrl)));
   if (hUrl != NULL)
      {
      nBuffLen = sizeof(nSize);
      if (HttpQueryInfo(hUrl,
                        HTTP_QUERY_CONTENT_LENGTH,
                        &nSize,
                        &nBuffLen,
                        0))
         Size=StrToInt(AnsiString(nSize));//ShowMessage("File size: "+AnsiString(nSize));
      else
         {
         MessageBoxA(Application->Handle , SysErrorMessage(GetLastError()).c_str(), "Error", 16);
         }
      InternetCloseHandle(hUrl);
      }
   InternetCloseHandle(hInet);
   }
return Size;
}
//---------------------------------------------------------------------------


P.S. дома пробовал эту программу на DialUp все проходит нормально, все запросы нормально обрабатываются и программы выдает реальный размер файла сразу, а на работе стоит выделенка через корпоративный прокси.

Как решить данную проблему???

Автор: Bima 18.12.2006, 13:50
Я сам разобрался.
Для того, что бы ответы от запросов нормально отображались, нужно использовать соответствующие флаги:
Код

__int64 GetInetFileSize(char *url)
{
HINTERNET hInet, hUrl;
char nSize[32];
__int64 Size;
DWORD nBuffLen;
Size=0; // сброс (можно использовать -1, тогда легче отследить, как сработала функция)

hInet = InternetOpen("Microsoft Internet Explorer",
                     INTERNET_OPEN_TYPE_PRECONFIG, // <- использовать этот флаг
                     NULL,
                     NULL,
                     NULL);
if (hInet != NULL)
   {
   Form1->Label3->Caption=IntToStr(Integer(hInet));
   hUrl = InternetOpenUrl(hInet,
                          url,
                          NULL,
                          NULL,
                          INTERNET_FLAG_EXISTING_CONNECT,  // <- использовать при текущем соединении
                          NULL);
   Form1->Label5->Caption=IntToStr(Integer(hUrl));
   if (hUrl != NULL)
      {
      nBuffLen = sizeof(nSize);
      if (HttpQueryInfo(hUrl,
                        HTTP_QUERY_CONTENT_LENGTH ,
                        &nSize,
                        &nBuffLen,
                        0))
         Size=StrToInt(AnsiString(nSize));//ShowMessage("File size: "+AnsiString(nSize));
      else
         {
         MessageBoxA(Application->Handle , SysErrorMessage(GetLastError()).c_str(), "Error", 16);
         }
      InternetCloseHandle(hUrl);
      }
   InternetCloseHandle(hInet);
   }
return Size;
}

Автор: Bima 2.2.2007, 07:09
Опять столкнулся с этой проблемой.
Задача такая: через определенные промежутки времени проверять на сервере размер файла и если он изменился, то закачать его.

код такой:
Код

NewSize=GetInetFileSize (MyURL.c_str()); //код этой подпрограммы смотрите выше
if (NewSize!=OldSize)
   {
   URLDownloadToFile(NULL, MyURL.c_str(), MyFile.c_str(), 0, 0 ); //Закачиваем файл
   OldSize=NewSize;
   }

Если запустить программу, то она хорошо работает, пока не закачает новый файл, а потом всегда показывает один и тот же размер, даже если размер файла изменился на сервере. После долгих поисков, я нашел, что программа кеширует файлы в папку:
c:\Documents and Settings\<имя пользователя>\Local Settings\Temporary Internet Files\Content.IE5\<произвольная папка>\файл

Если во время работы программы удалять файл, то программа начинает работать, как только что ее запустили. Я бы может быть обошел это ограничение (удалял бы эти файлы), но система сама создает <произвольная папки> с неизвестным названием.. ну типа QH8O6I5R

я попробовал другой код:
Код

NewSize=GetInetFileSize (MyURL.c_str()); //код этой подпрограммы смотрите выше
if (NewSize!=OldSize)
   {
   HINTERNET hInet, hUrl;
   hInet = InternetOpen("Microsoft Internet Explorer",
                     INTERNET_OPEN_TYPE_PRECONFIG,
                     NULL,
                     NULL,
                     NULL);
   if (hInet != NULL)
      {
      hUrl = InternetOpenUrl(hInet,
                          MyURL.c_str(),
                          NULL,
                          NULL,
                          INTERNET_FLAG_NO_CACHE_WRITE,//INTERNET_FLAG_RELOAD
                          NULL);
      if (hUrl != NULL)
         {
         URLDownloadToFile(NULL, MyURL.c_str(), MyFile.c_str(), 0, 0 ); //Закачиваем файл
         OldSize=NewSize;
         }
      else
         FDownExtr->SaveLog("Error URLDownloadToFile: "+SysErrorMessage(GetLastError()),2);   // Log-файл
      InternetCloseHandle(hUrl);
      }
   }

работает также (то есть до первого скачивания), только для внешних сайтов. Я для экспериментов использовал на соседнем компьютере web-сервер apache и туда поместил тестовый файл. Так вот, с этого сервера все нормально скачивается и определяется, а вот если я задаю внешний сервер (на narod.ru или какой другой), то программа работает до первого скачивания.
я пробовал разные флаги в функции InternetOpenUrl (INTERNET_FLAG_NO_CACHE_WRITE, INTERNET_FLAG_RELOAD и их комбинацию), но ничего не помогает.
Я предпологаю, что при больших задержках эта функция начинает кешировать. Может как нибудь убрать таймауты, что кеширования не было?
Как мне убрать кеширование??? 

Автор: _hunter 2.2.2007, 12:11
поробуй еще и INTERNET_FLAG_RESYNCHRONIZE с INTERNET_FLAG_PRAGMA_NOCACHE к тем двум добавить...

Автор: Bima 2.2.2007, 13:55
Попробовал. Не помогает smile
 делал так:
Код

// код подпрограммы (см. выше)

      hUrl = InternetOpenUrl(hInet,
                          MyURL.c_str(),
                          NULL,
                          NULL,
                          INTERNET_FLAG_RELOAD & INTERNET_FLAG_NO_CACHE_WRITE & INTERNET_FLAG_RESYNCHRONIZE & INTERNET_FLAG_PRAGMA_NOCACHE,
                          NULL);
      if (hUrl != NULL)
         {
         URLDownloadToFile(NULL, MyURL.c_str(), MyFile.c_str(), 0, 0 ); //Закачиваем файл
         OldSize=NewSize;
         }

// код подпрограммы (см. выше)

Заметил еще одну закономерность. Иногда если не трогать кеш, программа начинает работать через 4 часа. То есть такое ощущение, что данные в кеше становятся не актуальны через 4 часа.
Может быть то соединение, которое я создаю до команды URLDownloadToFile, не действуют на эту команду???
Посмотрел в MSDN, вроде привязок к текущему соединению нет.
Может какой другой командой можно файл скачать???

Добавлено @ 14:01 
P.S. забыл добавить, с локальным сервером Apache все работает нормально

Автор: Romikgy 2.2.2007, 14:02
Цитата(Bima @  2.2.2007,  12:55 Найти цитируемый пост)
INTERNET_FLAG_RELOAD & INTERNET_FLAG_NO_CACHE_WRITE & INTERNET_FLAG_RESYNCHRONIZE & INTERNET_FLAG_PRAGMA_NOCACHE,
                          

а разве не через | эту вещь надо объединять?

Автор: Bima 2.2.2007, 14:09
Цитата

а разве не через | эту вещь надо объединять? 


хм, это получяется если использовать или для объединения, то по логике вещей нужно читать так:
использовать или INTERNET_FLAG_RELOAD или INTERNET_FLAG_NO_CACHE_WRITE  и т.д.
но если рассуждать с точки зрения математики, то если складывать побитно  через "или" два числа 110 и 011 то получится 111,
а если складывать по "и", то 010.
Romikgy скорее всего ты прав, сейчас попробую проверить.

Автор: Bima 2.2.2007, 14:55
попробовал и "|" и "||" не помогает. Все равно в кэше появляются файлы. И программа не определяет правильно размер smile, соответственно и не скачивает уже обновленный файл.

Автор: dumb 2.2.2007, 15:19
достаточно INTERNET_FLAG_PRAGMA_NOCACHE | INTERNET_FLAG_NO_CACHE_WRITE, причем второй не является необходимым.

файл в кэше, связанный с ресурсом, можно удалить так: DeleteUrlCacheEntry(MyURL.c_str());

Автор: Bima 5.2.2007, 07:00
Цитата

DeleteUrlCacheEntry(MyURL.c_str()); 

Файл в кеше создается под именем не тем, с которым я качаю, а еще с префиксом [1], то есть если я качаю файл test.zip, то в кеше появляется файл test[1].zip или test[2].zip и т.д.

Автор: dumb 5.2.2007, 09:26
Цитата(Bima @  5.2.2007,  07:00 Найти цитируемый пост)
Файл в кеше создается под именем не тем, с которым я качаю, а еще с префиксом [1], то есть если я качаю файл test.zip, то в кеше появляется файл test[1].zip или test[2].zip и т.д. 

и что? - ты не заметил, что функция называется не DeleteFile, и что на вход функции дается не имя файла, а урл?

Автор: Bima 5.2.2007, 09:31
Цитата

и что? - ты не заметил, что функция называется не DeleteFile, и что на вход функции дается не имя файла, а урл? 

Признаю, свою ошибку!!! smile 
Вставил, эту команду в программу, все заработало.
Думаю, что тему можно считать закрытой.

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)