![]() |
|
|
|||||||
| Регистрация | << Правила форума >> | FAQ | Пользователи | Календарь | Поиск | Сообщения за сегодня | Все разделы прочитаны |
![]() |
|
|
Опции темы | Поиск в этой теме | Опции просмотра |
|
#1
|
|||
|
|||
|
Добрый день. Есть код загрузчика страниц(вызывается в поток):
Код:
function TLoader.LoadHtmlCode(const PageUrl: String):string;
var
ErrorData:string; (*ответ сервера в тестовом виде*)
ResponseCode:integer; (*ответ сервера в виде кода ошибки*)
begin
try
(*---------настройка параметров закачки-----------*)
FIdHttp.Request.UserAgent:=GetRandomUserAgent; (*получаем случайное значение Юзер-Агент*)
FIdHttp.Request.AcceptLanguage:='ru-ru,ru;q=0.8,en-us;q=0.5,en;q=0.3'; (*вроде нужно*)
FIdHttp.Request.AcceptCharSet:='windows-1251,utf-8;q=0.7,*;q=0.3'; (*вроде нужно*)
FIdHttp.ConnectTimeout:=10000;
FIdHttp.ReadTimeout:=10000;
FIdHttp.IOHandler:=FSSL;
FIdHttp.HandleRedirects:=True;
Result:=AnsiLowerCase(FIdHttp.Get(PageUrl));
except
Result:=PageUrl;
(*тут вызов ПРОЦ для записи ответа сервера и УРЛ в лог*)
end;
Exit; (*выход из функции. в РЕЗУЛЬТАТ содержится последнее значение*)
end;
end; 1. При высокой скорости трафика все работает нормально: - загрузка 100 УРЛ за 20...25 сек (10 потоков одновременно) - никаких утечек памяти практически все как предначертано работает 2. При наличие потребителя трафика(другой РС в сети с работающим ТОРРЕНТ, источник интернета - роутер 3 мбит\сек): - загрузка 97...100 УРЛ за 60...120 сек - один или два потока зависают(есть на форме индикатор числа работающих потоков)при закачке УРЛ и могут висеть часами, пока не закрыть программу - никакой зависимости от УРЛ нет, в одон тесте одни УРЛ не закачиваются в другом другие - еще одна особенность: в логе фиксируется ответ сервера. при наличие конкурента на трафик от 10 до 30 УРЛ не загружаются(то же различные, от теста к тесту), хотя ответ сервера = 200 (ну это не самая большая проблема, скоро будет добавлен код перезакачки УРЛ), но о чем то этот факт говорит? Внимание! Вопросы: 1. в чем причина такого поведения TidHttp? возможно надо что то настроить в параметрах загрузчика? 2. возможно ли ввести в поток загрузчика таймер типа: Код:
procedure TLoader.Execute; begin CallTimer; FIdHttp.Get(PageUrl); end; procedure TLoader.CallTimer; begin (*тут реализация таймера на 100 сек, но на чем? TTimer явно не подойдет*) Событие OnTimer вызывает FIdHttp.Socket.Close; (*если через 100 сек страница не закачается и поток не сдохнет принудительно закрыть idHTTP, поток после тоже закроется*) может кто подскажет реализацию таймера, на чем бы его сделать? end; почитал на форумах что нашел, похоже таймер единственный вариант решить эту проблему |
|
#2
|
|||
|
|||
|
Вообще, скорее всего, просто у тебя есть необработанное исключение, которое из потока никак себя внешне не проявляет. На самом деле поток уже закончился, а вот объект продолжает "висеть". Оберни все тело Execute в try...except и залогируй ошибку:
Код:
procedure TMyThread.Execute;
begin
Try
// весь твой код здесь
Except
On E : Exception Do
// здесь записать куда-нить, например в файл, текст ошибки E.Message
End;
end; |
| Этот пользователь сказал Спасибо lmikle за это полезное сообщение: | ||
Pcrepair (07.01.2013)
| ||
|
#3
|
|||
|
|||
|
lmikle, спасибо за подсказку, к сожалению она оказалась практически бесполезной в данном конкретном случае(но как метод разборки полетов), в частности сделал так:
Код:
procedure TLoader.Execute;
var Code:string;
begin
try
(*------------------------------*)
Code:=LoadPage(Url); (*ту вызов загрузчика*)
CS.Enter; (*вход в КС*)
try
gStore.Add(Code); (*передаем результат в ГП*)
Dec(CurrentNumOfTHreads); (*счетчик потоков*)
finally
Cs.Leave; (*выход из КС*)
end;
(*-----------------------------*)
except
On E:Exception do
ShowMessage(E.Message); (*просто вывести чего либо*)
end;
end;в связи с выше перечисленным вернемся к насущной проблеме: как правильно сделать таймер внутри потока, чиста внутри потока. конечно таймер будет обращаться к системе через КС, но как конкретно? кто нибуть в курсе? |
|
#4
|
||||
|
||||
|
Инди, как показала практика с одним моим парсером, любит падать и виснуть в самый неподходящий момент.
Решил переходом на WinHTTP, который имеет на порядок меньше ограничений, да и работает шустрее (WinAPI таки). Пример кода (winhttp.pas брать тут): Код:
uses
WinHTTP;
function LoadFile(server, url: WideString): WideString;
begin
var
hInet, hConn, hReq: Pointer;
buf: array of char;
bufSize, bufRead, p: cardinal;
begin
hInet := WinHttpOpen('UserAgent/1.0',0,nil,nil,0);
hConn := WinHttpConnect(hInet, PWideChar(server), INTERNET_DEFAULT_HTTP_PORT, 0);
hReq := nil;
repeat
if hReq <> nil then WinHttpCloseHandle(hReq);
repeat hReq := WinHttpOpenRequest(hConn, 'GET', PWideChar(url), 'HTTP/1.1', nil, nil, 0) until hReq <> nil;
while not WinHttpSendRequest(hReq, nil, 0, nil, 0, 0, 0) do;
until WinHttpReceiveResponse(hReq, nil);
bufSize := 0;
p := 0;
while WinHttpQueryDataAvailable(hReq, bufSize) do begin
SetLength(buf,p+bufSize);
if bufSize = 0 then break;
bufRead := 0;
WinHttpReadData(hReq, @buf[p], bufSize, bufRead);
inc(p,bufRead);
end;
WinHttpCloseHandle(hReq);
WinHttpCloseHandle(hConn);
WinHttpCloseHandle(hInet);
SetLength(buf,p+1);
Result := UTF8Decode(UTF8String(PChar(@buf[0])));
end;
procedure TForm1.Button1Click(Sender: TButton);
begin
MessageBoxW(0,PWideChar(LoadFile('delphisources.ru','/forum/index.php')),nil,0);
// Используем MessageBoxW для нормального отображения UTF-8
end;Последний раз редактировалось PhoeniX, 08.01.2013 в 09:48. |
| Этот пользователь сказал Спасибо PhoeniX за это полезное сообщение: | ||
Pcrepair (07.01.2013)
| ||
|
#5
|
|||
|
|||
|
а вот это:
- переадресация по 301 и 302, ответы сервера 404 500 502 и прочее самому делать прийдется? - выбор кодовой страницы самому делать прийдется?(хотя ттут видимо и с ИНДИ тоже) - запуск экземпляря загрузчика в потоке получится? хотя тут наверно косяков не будет WinHttp.pas - это интерфейс? для winhttp.dll там вообще как? ВЫНьХР, ВЫНь7 и 8 совместимость есть? мне нужно чтоб под любой из этих ОС все работало не в курсе? |
|
#6
|
||||
|
||||
|
Если верить MSDN (что я предпочитаю делать), поддерживается на всех виндах, начиная с XP.
Цитата:
С потоками проблем нет, у меня качает спокойно и в 70 с лишним потоков, даже без подвисаний и ожиданий. Кодовая страница - UTF-8 поддерживаются нативно благодаря WideString. Хотя, с Win1251 будут проблемы, но это быстро решается. Редиректы и ошибки не пробовал, но обрабатывать их довольно просто. Последний раз редактировалось PhoeniX, 07.01.2013 в 19:49. |
|
#7
|
|||
|
|||
|
Надо будет попробовать заменить код загрузчика от idHTTP на winInet
Спасибо за подсказку |
|
#8
|
||||
|
||||
|
WinInet не советую. Он ограничен 2 (или 4) потоками одновременно, зависит от конфигурации. Жалкая прослойка между WinHTTP и Internet Explorer-ом... WinHTTP имеет аналогичный интерфейс программирования, но ограничений нет...
|
|
#9
|
|||
|
|||
|
а в списке модулей есть WinInet
так это что иное чем WinInet, ICS, socket и прочее? winhttp.dll надо будет поискать информацию что это такое и еще, с HTTPs это будет как то работать? |
|
#10
|
|||
|
|||
|
Еще можно synapse попробовать. Я вот собираюсь (залодбала Indy с некоторыми вещами). Как минимум, ping реализуется практически не глядя (просто проверил, что работоспособна, кстати, на XE3).
|
|
#11
|
||||
|
||||
|
Цитата:
Код:
function LoadFileHTTPS(server, url: WideString): WideString;
begin
var
hInet, hConn, hReq: Pointer;
buf: array of char;
bufSize, bufRead, p: cardinal;
begin
hInet := WinHttpOpen('UserAgent/1.0',0,nil,nil,0);
hConn := WinHttpConnect(hInet, PWideChar(server), INTERNET_DEFAULT_HTTPS_PORT, 0); // HTTP -> HTTPS
hReq := nil;
repeat
if hReq <> nil then WinHttpCloseHandle(hReq);
repeat hReq := WinHttpOpenRequest(hConn, 'GET', PWideChar(url), 'HTTP/1.1', nil, nil, WINHTTP_FLAG_SECURE) until hReq <> nil;
// Флаг WINHTTP_FLAG_SECURE
while not WinHttpSendRequest(hReq, nil, 0, nil, 0, 0, 0) do;
until WinHttpReceiveResponse(hReq, nil);
bufSize := 0;
p := 0;
while WinHttpQueryDataAvailable(hReq, bufSize) do begin
SetLength(buf,p+bufSize);
if bufSize = 0 then break;
bufRead := 0;
WinHttpReadData(hReq, @buf[p], bufSize, bufRead);
inc(p,bufRead);
end;
WinHttpCloseHandle(hReq);
WinHttpCloseHandle(hConn);
WinHttpCloseHandle(hInet);
SetLength(buf,p+1);
Result := UTF8Decode(UTF8String(PChar(@buf[0])));
end;
procedure TForm1.Button1Click(Sender: TButton);
begin
MessageBoxW(0,PWideChar(LoadFileHTTPS('github.com','/')),nil,0);
end; |
| Этот пользователь сказал Спасибо PhoeniX за это полезное сообщение: | ||
Pcrepair (08.01.2013)
| ||