Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Обрывы связи с сервером при закачки файлов, Как с этим боротся? 
:(
    Опции темы
CLIPSA
Дата 7.1.2007, 23:56 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 126
Регистрация: 6.10.2006

Репутация: 1
Всего: 2



Я использую для закачки компонент инди:
Код

 TFileStream* fs = new TFileStream("С:\may.mdb", fmCreate);
   IdHTTP1->Get("http://oevoev.jino-net.ru/may.mdb", fs);
    delete fs;


Если файл маленький (около 20кб), то файл закачивается без проблем. Но если файл допустим 5 Мб, то файл не закачивается полностью. Причина  в том что иногда обрывается соединение. Программы для закачек типа ReGet Deluxe и ей подобные при разрыве соедениения с сервером как-то запоминают позицию на чём остоновилась закачка и потом опять соединяется и продолжает качать с того метса, где был остонов. И так пока не закачается весь файл.

А как же быть мне  smile  Я незнаю как при помощи фунции IdHTTP1->Get решить это.
Может быть кто-то сталкивался с этим  smile Если да, то раскажите мне как победить эту проблему. Очень прошу.
 
PM MAIL   Вверх
CLIPSA
Дата 8.1.2007, 18:05 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 126
Регистрация: 6.10.2006

Репутация: 1
Всего: 2



Что ни кто не знает?  smile 
PM MAIL   Вверх
codelord
Дата 8.1.2007, 20:49 (ссылка) |    (голосов:1) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 777
Регистрация: 7.5.2005
Где: ты моя темноглаза я где?!

Репутация: 16
Всего: 39



Сам не пробовал докачивать файлы, покажу статью как с помощью wininet это делать.
Если что не получится спрашивай.
Код



WinInet: скачка\докачка файлов по http-протоколу

Wininet представляет собой api для доступа к протоколам интернет, таким как http, ftp, gopher. С помощью данного набора api можно с легкостью скачивать файлы, страницы, писать разные интересные программы, не сильно задумываясь о таких вещах, как сокеты, таймауты, протоколы, etc. В данной статье будет рассмотрено, как закачать файл по протоколу http, используя функции wininet'а.

Для начала нам нужно открыть сессию, т.е. вызвать функцию InternetOpen:
INTERNETAPI
HINTERNET
WINAPI
InternetOpen(
    IN LPCTSTR lpszAgent,
    IN DWORD dwAccessType,
    IN LPCTSTR lpszProxy OPTIONAL,
    IN LPCTSTR lpszProxyBypass OPTIONAL,
    IN DWORD dwFlags
    );
 

все, что мы здесь устанавливаем (остальные значения можно смело забивать нулем), это 1ый параметр lpszAgent - то, как нас будет определять сервер (IE, Opera, etc.) и 2ый параметр - тип доступа (прямой, прокси или "предустановленный"). Чаще всего будет использоваться "предустановленный" тип соединения, т.е. настройки соединения будут браться из системного реестра. Этот тип соответствует константе INTERNET_OPEN_TYPE_PRECONFIG. Настройки же можно изменить в броузере Internet Explorer зайдя в Tools->Internet Options->Connections. В случае, если вам надо, например, использовать другой прокси, то используйте dwAccessType=INTERNET_OPEN_TYPE_PROXY. Пример:
HINTERNET session = InternetOpen("Our Agent", 
  INTERNET_OPEN_TYPE_PROXY, 
  "192.168.0.1:3128", /* наша прокся 192.168.0.1 порт 3128 */
  "", 0);
 

Также можно посмотреть в сторону функции InternetSetOption:
BOOLAPI
InternetSetOption(
    IN HINTERNET hInternet OPTIONAL,
    IN DWORD dwOption,
    IN LPVOID lpBuffer,
    IN DWORD dwBufferLength
    );

INTERNET_PROXY_INFO pi;
pi.dwAccessType = INTERNET_OPEN_TYPE_PROXY;
pi.lpszProxy = "192.168.0.1:3128";
pi.lpszProxyBypass = "";
InternetSetOption(session, INTERNET_OPTION_PROXY, (LPVOID)&pi, sizeof(pi)); // пример аналогичный предыдущему :)
 

Сессия открыли, теперь можно получить хэндл необходимого файла в сети. Для этого нам нужна функция InternetOpenUrl. Эта функция работает независимо от протокола (wininet поддерживает протоколы http, ftp, gopher).
INTERNETAPI
HINTERNET
WINAPI
InternetOpenUrl(
    IN HINTERNET hInternet,
    IN LPCTSTR lpszUrl,
    IN LPCTSTR lpszHeaders OPTIONAL,
    IN DWORD dwHeadersLength,
    IN DWORD dwFlags,
    IN DWORD dwContext
    );
 

В качестве параметров функция принимает хэндл открытой сессии (см. InternetOpen), строчку с указанным файлом\страницей. Остальные параметры нам не важны (опять нули). Кстати, из всех функций, нами используемых, эта функция самая тормозная. Думаю, не надо обьяснять почему.

Все файл "открыли", ошибок при этом не возникло, можно из этого файла что-нибудь прочитать. Для этого нам нужна функция InternetReadFile, к-рая очень похоже на ReadFile для локальных файлов. Вот ее описание:
BOOLAPI
InternetReadFile(
    IN HINTERNET hFile,
    IN LPVOID lpBuffer,
    IN DWORD dwNumberOfBytesToRead,
    OUT LPDWORD lpdwNumberOfBytesRead
    );
 

На вход подается хэндл файла (hFile), буфер для чтения (lpBuffer), сколько байт прочитать (dwNumberOfBytesToRead). В моем примере качаются блоки по 64 кбайт. Если все прошло удачно, то функция возвратит TRUE и число прочитанных байт в lpdwNumberOfBytesRead. В противном случае, это может означать, что произошел разрыв связи, мы прочитали файл до конца либо что-то еще. Если произошел обрыв связи, то нам нужно сделать реконнект (закрыть сессию и открыть ее вновь через некоторый промежуток времени), вернуть file pointer на то место, до к-рого мы прочитали файл, и продолжить читать файл. Для "перемещения" по файлу нам нужен аналог функции SetFilePointer для wininet'a - InternetSetFilePointer. 
INTERNETAPI
DWORD
WINAPI
InternetSetFilePointer(
    IN HINTERNET hFile,
    IN LONG  lDistanceToMove,
    IN PVOID pReserved,
    IN DWORD dwMoveMethod,
    IN DWORD dwContext
    );
 

lDistanceToMove указывает на сколько сдвинуть fp относительно начала (dwMoveMethod=FILE_BEGIN), текущей позиции (FILE_CURRENT) или конца файла (FILE_END).

После того, как файл успешно закачен, хорошим тоном является закрытие всех открытых ресурсов. Для этого используется аналог функции CloseHandle - InternetCloseHandle. 

Также для определения разных состояний потребуется функция HttpQueryInfo. Синтаксис такой:
BOOLAPI
HttpQueryInfo(
    IN HINTERNET hRequest,
    IN DWORD dwInfoLevel,
    IN OUT LPVOID lpBuffer OPTIONAL,
    IN OUT LPDWORD lpdwBufferLength,
    IN OUT LPDWORD lpdwIndex OPTIONAL
    );
 

Это универсальная функция, к-рая позволяет определить много различных параметров (подробности см. в wininet.h). В примере она используется для определения размера файла и определения нужна ли авторизация на сервере для скачки файла. В качестве параметров требуется hRequest, хэндл открытый через InternetOpen или HttpOpenRequest, dwInfoLevel - флаги, к-рые определяют действие функции (определение размера файла - HTTP_QUERY_CONTENT_LENGTH|HTTP_QUERY_FLAG_NUMBER, проверка на ощибки - HTTP_QUERY_FLAG_NUMBER | HTTP_QUERY_STATUS_CODE, см также wininet.h), lpBuffer - буфер, в к-рый будет возвращен результат, lpdwBufferLength - его размер (буфера), lpdwIndex - как всегда 0.

Возможнен случай, когда нужна авторизация на сервере. Тоже не проблема: проверяется это с помощью функции HttpQueryInfo, а логин\пасс устанавливается опять с помощью InternetSetOption. 
// fd - хэндл файла
// login - имя изера 
// pass - пароль
char status[32];
unsigned long size = sizeof(status)/sizeof(char);
if (HttpQueryInfo(fd, HTTP_QUERY_FLAG_NUMBER|HTTP_QUERY_STATUS_CODE, status, &size, NULL)) {
  if ((*(int *)status)==HTTP_STATUS_PROXY_AUTH_REQ) {
    InternetSetOption(fd, INTERNET_OPTION_PROXY_USERANAME, login, strlen(login));
    InternetSetOption(fd, INTERNET_OPTION_PROXY_PASSWORD, pass, strlen(pass));
  }
}
 


С функциями определились, теперь можно показать пример закачки файла:
// большинство проверок пропущено
HINTERNET session, file;
session = InternetOpen("Our Agent", PRE_CONFIG_INTERNET_ACCESS, 0, 0, 0);
file = InternetOpenUrl(session, "http://www.oursite.com/ourfile.zip", 0, 0, 0, 0);
char buf[64000];
unsigned long len, offs;
offs = 0;
do {
   InternetReadFile(file, buf, sizeof(buf), &len);
   if (len>=0) {
      // данные прочитались
      // можно с ними что-нибудь сделать, например, записать в файл
      offs += len;
   } else {
      // анализируем ошибку
      int error = GetLastError();
      // пытаемся восстановить закачку
      // закрываем сессию
      InternetCloseHandle(file);
      InternetCloseHandle(session);
      // ждем какое-то время, например, 1 секунду
      Sleep(1000);
      // открываем сессию по-новой
      session = InternetOpen("Our Agent", PRE_CONFIG_INTERNET_ACCESS, 0, 0, 0);
      file = InternetOpenUrl(session, "http://www.oursite.com/ourfile.zip", 0, 0, 0, 0);
      // перемещаем указатель
      InternetSetFilePointer(file, offs, 0, FILE_BEGIN, 0);
      // продолжаем качать файл
   }
} while (len);
InternetCloseHandle(file);
InternetCloseHandle(session);
 


Прикрепренный проект представляет собой простенькую однопоточную качалку, к-рая тем не менее поддерживает докачку файла. В проекте показана работа с wininet'ом и ini-файлами (для некоторых личностей и для этого нужен фак ;-). Программка закачивает один файл частями по BUF_SIZE и записывает их в файл. Также в конфиг-файл программки (download.exe.ini) пишется сколько закачано, и в случае чего по этим данным происходит "откат" закачки. Также есть проверка ошибок (простая , определение длины файла, поддерживаются сайты с авторизацией. Проект нормально компилиться под gcc(mingw), bc5.5 и vc6.0\7.1. c-like style.

Некоторые замечания:
1. Wininet имеет ограничение на число соединений для одного сервера (2 или 4). Лечиться здесь (максимум, как я понимаю, все же есть, не больше 10):
HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Internet Settings\MaxConnectionsPer1_0Server
HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Internet Settings\MaxConnectionsPerServer
HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Internet Settings\MaxConnectionsPer1_0Server
HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Internet Settings\MaxConnectionsPerServer
 


2. Нередко бывает, что нужно пропарсить строчку с урлой на предмет того, какой протокол используется, на каком порту, какой сервер, какой файл, etc. Можно это делать самому, но в wininet'e уже есть схожие функции. Вот небольшой кусок кода из mfc (немного переработаный мной под свои нужды), к-рый это делает:
static int ParseUrlEx(char *pstrURL, LPURL_COMPONENTS lpComponents, 
               DWORD& dwServiceType, INTERNET_PORT& nPort, DWORD dwFlags)
{
    assert(lpComponents!=NULL && pstrURL!=NULL);
    if (lpComponents==NULL || pstrURL==NULL)
        return 0;

    assert(lpComponents->dwHostNameLength==0 || lpComponents->lpszHostName);
    assert(lpComponents->dwUrlPathLength==0 || lpComponents->lpszUrlPath);
    assert(lpComponents->dwUserNameLength==0 || lpComponents->lpszUserName);
    assert(lpComponents->dwPasswordLength==0 || lpComponents->lpszPassword);

    LPTSTR pstrCanonicalizedURL;
    TCHAR szCanonicalizedURL[INTERNET_MAX_URL_LENGTH];
    DWORD dwNeededLength = INTERNET_MAX_URL_LENGTH;
    int bRetVal;
    BOOL bMustFree = FALSE;
    DWORD dwCanonicalizeFlags = dwFlags & (ICU_NO_ENCODE | ICU_DECODE | 
        ICU_NO_META | ICU_ENCODE_SPACES_ONLY | ICU_BROWSER_MODE);
    DWORD dwCrackFlags = dwFlags & (ICU_ESCAPE | ICU_USERNAME);

    bRetVal = InternetCanonicalizeUrl(pstrURL, szCanonicalizedURL,
        &dwNeededLength, dwCanonicalizeFlags);

    if (!bRetVal) {
        if (GetLastError()!=ERROR_INSUFFICIENT_BUFFER)
            return 0;

        pstrCanonicalizedURL = (LPTSTR)malloc(dwNeededLength*sizeof(TCHAR));
        bMustFree = TRUE;
        bRetVal = InternetCanonicalizeUrl(pstrURL, pstrCanonicalizedURL,
            &dwNeededLength, dwCanonicalizeFlags);
        if (!bRetVal) {
            free(pstrCanonicalizedURL);
            return 0;
        }
    } else {
        pstrCanonicalizedURL = szCanonicalizedURL;
    }

    bRetVal = InternetCrackUrl(pstrCanonicalizedURL, 0, 
        dwCrackFlags, lpComponents);
    if (bMustFree) free(pstrCanonicalizedURL);

#define PARSEURLX(x) case x: dwServiceType = x; break;

    if (!bRetVal)
        dwServiceType = INTERNET_SCHEME_UNKNOWN;
    else {
        nPort = lpComponents->nPort;
        switch (lpComponents->nScheme)
        {
            PARSEURLX(INTERNET_SCHEME_FTP);
            PARSEURLX(INTERNET_SCHEME_GOPHER);
            PARSEURLX(INTERNET_SCHEME_HTTP);
            PARSEURLX(INTERNET_SCHEME_HTTPS);
            PARSEURLX(INTERNET_SCHEME_FILE);
            PARSEURLX(INTERNET_SCHEME_NEWS);
            PARSEURLX(INTERNET_SCHEME_MAILTO);
            default:
                dwServiceType = INTERNET_SCHEME_UNKNOWN;
        }
    }
    return bRetVal;
}

int ParseUrl(char *pstrURL, DWORD& dwServiceType, 
             char *strServer, char *strObject, INTERNET_PORT& nPort)
{
    dwServiceType = INTERNET_SCHEME_UNKNOWN;
    if (!pstrURL) return 0;

    URL_COMPONENTS urlComp;
    memset((void *)&urlComp, 0, sizeof(URL_COMPONENTS));
    urlComp.dwStructSize = sizeof(URL_COMPONENTS);
    urlComp.dwHostNameLength = INTERNET_MAX_URL_LENGTH;
    urlComp.lpszHostName = strServer;
    urlComp.dwUrlPathLength = INTERNET_MAX_URL_LENGTH;
    urlComp.lpszUrlPath = strObject;
    
    return ParseUrlEx(pstrURL, &urlComp, dwServiceType, 
        nPort, ICU_BROWSER_MODE);
}
 



Это сообщение отредактировал(а) codelord - 8.1.2007, 20:52


--------------------
Доступен поиск по исходным кодам в GOOGLE.
http://www.google.com/codesearch
PM MAIL   Вверх
CLIPSA
Дата 10.1.2007, 21:53 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 126
Регистрация: 6.10.2006

Репутация: 1
Всего: 2



Супер!!!!!!!   smile  Классная статья, всё подробно и разжёвано  smile  smile 
Теперь понятно стало как докачивать и ясно теперь как ProgressBar закачки прикрутить.  smile Спасибо тебе огрмное codelord, . 
К сожалению у меня не хватает постов чтоб плюсик тебе добавить smile 



PM MAIL   Вверх
codelord
Дата 11.1.2007, 00:16 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 777
Регистрация: 7.5.2005
Где: ты моя темноглаза я где?!

Репутация: 16
Всего: 39



Цитата(CLIPSA @  10.1.2007,  17:53 Найти цитируемый пост)
К сожалению у меня не хватает постов чтоб плюсик тебе добавить 

У тебя все еще впереди smile


--------------------
Доступен поиск по исходным кодам в GOOGLE.
http://www.google.com/codesearch
PM MAIL   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Правила форума "С++ Builder"
Rrader

Запрещается!

1. Публиковать ссылки на вскрытые компоненты

2. Обсуждать взлом компонентов и делиться вскрытыми компонентами

  • Литературу по С++ Builder обсуждаем здесь
  • Действия модераторов можно обсудить здесь
  • С просьбами о написании курсовой, реферата и т.п. обращаться сюда
  • Настоятельно рекомендуем заглянуть в DRKB (Delphi Russian Knowledge Base) - крупнейший в рунете сборник материалов по Дельфи


Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, Rrader.

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | C++ Builder | Следующая тема »


 




[ Время генерации скрипта: 0.0498 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.