Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Начинающим";
Текущий архив: 2013.09.15;
Скачать: [xml.tar.bz2];

Вниз

Проблемы с потоками при закачке страниц   Найти похожие ветки 

 
Pcrepair ©   (2012-12-27 11:20) [0]

Добрый день.
Есть функция вида function LoadPage(const Url:string):string; для закачки страниц на базе idHHP.Get, которая обеспечивает:
- закачку страниц с фреймами
- закачку страниц по HTTPs
- смену Request.UserAgent (доп. функция) по Random из списка агентов
- подавление исключений в коде idHHP.Get с записью в лог причин
- вывод сообщений о утечке памяти при закрытии Арр
Сама по себе функция работает нормально, загружает все страницы и без утечки памяти.

Есть код запуска этой функции в многопоточном режиме:

unit Main;
....
implementation
{$R *.dfm}
uses uLoadPage,uGlobalVar;

(*нажимает эту кнопку и понеслось*)
procedure TMainForm.Btn_StartLoadURLsClick(Sender: TObject);
var
UrlList:TStringList; (*эквивалент передаваемого массива строк из ПМ*)
i:integer;
Url:string; (*строка = УРЛ из массива*)
begin
  UrlList:=TStringList.Create;
  UrlList.Text:=Mm_InsSMUrls.Text; (*ввод массива строк УРЛ*)
    (*----ЦИКЛ мульти закачки страниц по числу УРЛ в Mm_InsSMUrls---*)
    for i := 0 to UrlList.Count-1 do
      begin
         Url:=UrlList[i]; (*передача УРЛ*)
         Loader(Url); (*вызов процедуры запуска потока закачки страницы*)
         Sleep(10);  (*страховка от перегрева процессора а также от толпы потоков, которые мешают друг другу?*)
      end;
  FreeAndNil(UrlList);
end;


unit uLoadPage;
interface
uses SysUtils, uThreadLoader, Classes;
Procedure Loader(Url:string);
implementation
Procedure Loader(Url:string);
var ThreadLdr: TLoader;
begin
   ThreadLdr:=Tloader.Create(True);
   ThreadLdr.Priority:=tpNormal;  
   ThreadLdr.FreeOnTerminate:=True;
   ThreadLdr.Url:=Url;
   ThreadLdr.Start;
 end;
end.


unit uThreadLoader;
interface
uses
 System.Classes, idHTTP, SysUtils, Dialogs;
type
 TLoader = class(TThread)
 private
    FUrl:string;
    FHtml:string;
   { Private declarations }
 protected
   procedure Execute; override;
   procedure CallStore;
   function LoadHtmlCode(const Url:string):string;
 public
   property Url: string read FUrl write FUrl;  (*свойство класа, доступное для всей программы*)
   property Html: string read FHtml write FHtml;
 end;

implementation
uses uPageLoader, uLoadPage, uGlobalVar;

function TLoader.LoadHtmlCode(const Url:string):string;
begin
 Result:=LoadPage(Url); (*вызываем функцию загрузки страницы из uPageLoader*)
end;

procedure TLoader.CallStore;
begin
  gStore.Add(Html); (*ввод новой строки в ГлобПерем*)
end;

procedure TLoader.Execute;
begin
  Html:=LoadHtmlCode(Url);  (*загрузка страницы в Поле Класса(свойство)*)
   CS.Enter;  (*вход в КС*)
      CallStore; (*передаем результат в ГП*)
   Cs.Leave;  (*выход из КС*)
end;

end.


unit uPageLoader;
interface
uses Classes, SysUtils, idHTTP, StrUtils, IdSSL, IdSSLOpenSSL;
   function LoadPage(const Url:string):string;  (*Основная функция Юнита*)
   procedure ErrorLog(Url:string);
   function LoadHtmlPage(const PageUrl:string):string;
   function DelJS(const Code:string):string;
   function RestoreFrame(const Code:string):string;
   function RestoreFullUrl(const Code:string; const RootUrl:string):string;
   function GetRandomUserAgent: string;
   var
   Loader:TidHTTP;
   SSL:TIdSSLIOHandlerSocketOpenSSL;

implementation
тут много чего, но все работает, смотри в начало
end.


unit uGlobalVar;
interface
uses Classes, SysUtils, SyncObjs;
var
gStore: TStringList=nil; (*ГП для хранения закачанных страниц*)
CS:TCriticalSection; (*используем КС для передачи результата в основной поток*)
implementation

initialization
  gStore:=TStringList.Create;
  gStore.Duplicates:=dupAccept;
  gStore.Sorted:=False;
  Cs:=TCriticalSection.Create;
finalization
 FreeAndNil(gStore);
 FreeAndNil(CS);
end.


Результат:
В режиме отладки видно что возникает множество самых различных ошибок:
- First chance exception at $00407466. Exception class $C0000005 with message "access violation at 0x00407466: read of address 0x000000a4". Process Loader_VER06.exe (2012)
- First chance exception at $7C812AFB. Exception class EIdHTTPProtocolException with message "Set-Cookie: dle_password=deleted; expires=Tue, 27-Dec-2011 20:37:50 GMT; path=/; domain=.freeseller.ru; httponly". Process Loader_VER06.exe (2012)
First chance exception at $00629F8C. Exception class $C0000005 with message "access violation at 0x00629f8c: read of address 0x00000148". Process Loader_VER06.exe (2012)
- First chance exception at $7C812AFB. Exception class EOSError with message
"System Error.  Code: 123. Синтаксическая ошибка в имени файла, имени папки или метке тома".
Process Loader_VER06.exe (2012)
- First chance exception at $7C812AFB. Exception class EIdNotASocket with message
"Socket Error # 10038
Socket operation on non-socket.".
Process Loader_VER06.exe (2012)

В рабочем режиме, за счет подавления исключений, все это конечно не вылазит, но:
- закачиваются не все страницы(хотя все УРЛ валидные и функцией закачки закачиваются без вопросов)
- после закрытия Арр выводится сообщение о многочисленных маленьких утечках памяти

По теории потоки не должны пересекаться. каждый имеет свою память. вывод результата через КС. такое впечетление что потоки как то мешают друг другу
Внимание!!! Вопрос: в чем может быть причина появления исключений и утечки памяти именно в режиме многопотоковой закачки?


 
brother ©   (2012-12-27 11:45) [1]

> исключений и утечки памяти

исключения дают утечки...


 
Сергей М. ©   (2012-12-27 11:51) [2]

В упор не видно защиты глоб.ресурса gStore критической секцией.
Ты объект Cs вообще зачем создавал, не для этого ли как раз ?


 
Игорь Шевченко ©   (2012-12-27 11:51) [3]


> Вопрос: в чем может быть причина появления исключений и
> утечки памяти именно в режиме многопотоковой закачки?


Наверное в режиме отладки и строки, на которых проиходит исключение, показываются.

Не томи.


 
icWasya ©   (2012-12-27 11:55) [4]

Ну а в однопоточном режиме всё работает?
Ну то есть вот так
Procedure Loader(Url:string);
var ThreadLdr: TLoader;
begin
  ThreadLdr:=Tloader.Create(True);
  ThreadLdr.Priority:=tpNormal;  
  ThreadLdr.FreeOnTerminate:=True;
  ThreadLdr.Url:=Url;
  (*ThreadLdr.Start; вместо этого*)
  ThreadLdr.Execute;//<<==-- вот это
  ThreadLdr.Free;//<<==--
end;


 
Сергей М. ©   (2012-12-27 12:32) [5]


> вывод результата через КС


procedure TLoader.CallStore;
begin
  cs.Enter;
  try
    gStore.Add(Html); // вот теперь ресурс действительно защищен, никакие утечки теперь не грозят
  finally
    cs.Leave;
  end;
end;


 
Сергей М. ©   (2012-12-27 12:34) [6]

Разумеется "читающий" поток, тот который "выгребает" все это хозяйство из gStore, точно так же обязан входить в КС при этом.


 
anonims   (2012-12-27 12:52) [7]

В одном потоке все работает  => LoadPage не потокобезоасна. (использует и меняет не локальные данные).
function TLoader.LoadHtmlCode(const Url:string):string;
begin
Result:=LoadPage(Url); (*вызываем функцию загрузки страницы из uPageLoader*)
end;

unit uPageLoader;
interface
uses Classes, SysUtils, idHTTP, StrUtils, IdSSL, IdSSLOpenSSL;
  function LoadPage(const Url:string):string;  (*Основная функция Юнита*)

  var
  Loader:TidHTTP;
  SSL:TIdSSLIOHandlerSocketOpenSSL;

использование одного Loader, SSL для ВСЕХ потоков.


> тут много чего, но все работает, смотри в начало

тоже все глобальные объекты едины для всех потоков.


 
Pcrepair ©   (2012-12-27 14:03) [8]

anonims

> использование одного Loader, SSL для ВСЕХ потоков.

что ты имеешь ввиду? что нужно написать одинаковый код для скажем 10 потоков и для каждого прописать свой idHTTP, типа
idHTTP_1
idHTTP_2 и так далее и для каждого свое создание-уничтожение и все прочее?
++++++++++++++++++++++++++++++
Сергей М.

> Разумеется "читающий" поток, тот который "выгребает" все
> это хозяйство из gStore, точно так же обязан входить в КС
> при этом.

все правильно конечно, но в текущей ситуации(стенд) обращение к накопителю идет  вручную только после окончания работы всех потоков(контроль по диспетчеру задач), так что к описанным проблемам это пока не имеет отношения. вместе с тем, кто знает программу более функциональную чем Диспетчер задач, для наблюдения за потоками выбранного приложения?

и еще вопрос: там перем Html прописана как свойство класса, хотя можно прописать ее ка переменную в ПАБЛИК. в чем разница? и как правильно
+++++++++++++++++++++++++++++
Игорь Шевченко
там выводит код из модулей ИНДИ
типа

unit IdSSLOpenSSL

procedure TIdSSLIOHandlerSocketOpenSSL.ConnectClient;
var
 LPassThrough: Boolean;
begin

 (*RLebeau 1/11/07:
 In case a proxy is being used, pass through any data from the base class unencrypted when setting up that connection.  
 ///В случае, если используется прокси-сервер, пройти через любые данные из базового класса, незашифрованные при создании связи
 We should do this anyway since SSL hasn"t been initialized yet!
 ///Мы должны сделать это в любом случае, поскольку SSL не была инициализирована
 *)

 LPassThrough := fPassThrough;
 fPassThrough := True;
 try
   inherited ConnectClient;  (*исключение*)
 finally
   fPassThrough := LPassThrough;
 end;
 DoBeforeConnect(Self);
 // CreateSSLContext(sslmClient);
 // CreateSSLContext(SSLOptions.fMode);
 StartSSL;
end;
Только в многопоточном режиме исключение?
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Socket Error 10056
модуль IdStack
сообщение:
procedure TIdStack.RaiseSocketError(AErr: integer);
begin
 (*
   RRRRR    EEEEEE   AAAA   DDDDD         MM     MM  EEEEEE    !!  !!  !!
   RR  RR   EE      AA  AA  DD  DD        MMMM MMMM  EE        !!  !!  !!
   RRRRR    EEEE    AAAAAA  DD   DD       MM MMM MM  EEEE      !!  !!  !!
   RR  RR   EE      AA  AA  DD  DD        MM     MM  EE
   RR   RR  EEEEEE  AA  AA  DDDDD         MM     MM  EEEEEE    ..  ..  ..

   Please read the note in the next comment.
 *)
 if AErr = Id_WSAENOTSOCK then begin
   // You can add this to your exception ignore list for easier debugging.
   // However please note that sometimes it is a true error. Your program
   // will still run correctly, but the debugger will not stop on it if you
   // list it in the ignore list. But for most times its fine to put it in
   // the ignore list, it only affects your debugging.
   raise EIdNotASocket.CreateError(AErr, WSTranslateSocketErrorMsg(AErr));
 end;
 (*
   It is normal to receive a 10038 exception (10038, NOT others!) here when
   *shutting down* (NOT at other times!) servers (NOT clients!).

   If you receive a 10038 exception here please see the FAQ at:
   http://www.IndyProject.org/

   If you insist upon requesting help via our email boxes on the 10038 error
   that is already answered in the FAQ and you are simply too slothful to
   search for your answer and ask your question in the public forums you may be
   publicly flogged, tarred and feathered and your name may be added to every
   chain letter / EMail in existence today."

   Otherwise, if you DID read the FAQ and have further questions, please feel
   free to ask using one of the methods (Carefullly note that these methods do
   not list email) listed on the Tech Support link at:
   http://www.IndyProject.org/

   RRRRR    EEEEEE   AAAA   DDDDD         MM     MM  EEEEEE    !!  !!  !!
   RR  RR   EE      AA  AA  DD  DD        MMMM MMMM  EE        !!  !!  !!
   RRRRR    EEEE    AAAAAA  DD   DD       MM MMM MM  EEEE      !!  !!  !!
   RR  RR   EE      AA  AA  DD  DD        MM     MM  EE
   RR   RR  EEEEEE  AA  AA  DDDDD         MM     MM  EEEEEE    ..  ..  ..
 *)
 raise EIdSocketError.CreateError(AErr, WSTranslateSocketErrorMsg(AErr));
end;
а вот что это значит и что с этим делать?


 
Сергей М. ©   (2012-12-27 14:16) [9]


> к описанным проблемам это пока не имеет отношения


"пока" может и не имеет, тебе виднее.
А потом поимеет - попросту забудешь про синхронизацию, как сейчас "забыл" про нее в CallStore.
Лучше таки сразу предусмотреть синхронизацию для всех потенциально возможных случаев. И обратить при этом внимание на TMultiReadExclusiveWriteSynchronizer как возможно более разумную альтернативу TCriticalSection.


 
RWolf ©   (2012-12-27 14:31) [10]


> что нужно написать одинаковый код для скажем 10 потоков
> и для каждого прописать свой idHTTP, типаidHTTP_1idHTTP_2
> и так далее и для каждого свое создание-уничтожение и все
> прочее?

ну, а как думаешь, данные глобального объекта idHTTP каким-то волшебным образом избегут разрушения, когда их модифицируют несколько потоков?
для каждого свой, конечно.


 
Сергей М. ©   (2012-12-27 14:42) [11]


> перем Html прописана как свойство класса, хотя можно прописать
> ее ка переменную в ПАБЛИК. в чем разница? и как правильно


А зачем она вообще нужна именно в описании класса ? Кто к ней обращается кроме членов самого класса TLoader ?
Судя по приведенному коду это вообще переменная временного назначения, место которой  - в стеке, т.е. среди локальных переменных подпрограмм.


 
Pcrepair ©   (2012-12-27 14:59) [12]


> А зачем она вообще нужна именно в описании класса ? Кто
> к ней обращается кроме членов самого класса TLoader ?

это рудимент предыдущих экспериментов

получается нужно писать код нескольких потоков, имеющих каждый свой idHTTP.Get и весь код обработки страницы, а не вызывать функции из доп. модулей? чтоб гарантированно не было исключений?

может тогда уже свой класс правильней написать? с использованием внутри этого класса потоков.
создавать потомок класса, передавать ему значение(УРЛ) + написать класс НАКОПИТЕЛЬ в который передавать асинхронно результат работы
с ООП знаком пока только теоритически


 
bems ©   (2012-12-27 15:04) [13]

вызывать функции других модулей можно, но нельзя при этом обращаться к общим данным без синхронизации.
например можно сделать функции LoadPage еще один параметр типа TidHttp и передавать в него экземпляр, с которым работает только вызывающий поток


 
Сергей М. ©   (2012-12-27 15:44) [14]


> а не вызывать функции из доп. модулей?


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


 
Pcrepair ©   (2012-12-27 17:26) [15]


> bems ©   (27.12.12 15:04) [13]
> вызывать функции других модулей можно, но нельзя при этом
> обращаться к общим данным без синхронизации.
> например можно сделать функции LoadPage еще один параметр
> типа TidHttp и передавать в него экземпляр, с которым работает
> только вызывающий поток


это типа

function TForm1.LoadPage(const S:string; idHttp: TidHttp):string;
begin
  idHttpLoad := TIdHTTP.Create(nil);
 try
   LoadPage := (AnsiLowerCase(idHttpLoad.Get(S)));
 finally
    idHttpLoad.Free;
 end;
end;


 
bems ©   (2012-12-27 18:56) [16]

типа
function LoadPage(const Url: String; IdHttp: TIdHttp): String;
begin
 Result := AnsiLowerCase(IdHttp.Get(Url))
end;

function TLoader.LoadHtmlCode(const Url: String): String;
begin
Result:=LoadPage(Url, FIdHttp)
end;
, где FIdHttp - поле TLoader, присваиваемое в конструкторе


 
Pcrepair ©   (2012-12-27 20:07) [17]

что то такую форму записи Result:=LoadPage(Url, FIdHttp) нигде в букварях не встречал

FIdHttp - это в

TLoader = class(TThread)
private
   FIdHttp:TidHTTP;

объявить?


 
bems ©   (2012-12-27 20:30) [18]

объявить. и в конструкторе присвоить FIdHttp := TIdHTTP.Create(nil);
в деструкторе соответственно освободить
что именно не встречал?


 
Pcrepair ©   (2012-12-27 21:31) [19]

вот это: (Url, FIdHttp)
но не будем отвлекаться на пустяки, итого нужно следующее

type
 TLoader = class(TThread)
 private
    FUrl:string;
    FIdHttp:TidHTTP;
 protected
   procedure Execute; override;
   function TLoader.LoadHtmlCode(const Url: String): String;
 public
   property Url: string read FUrl write FUrl;  (*свойство класа, доступное для всей программы*)
   constructor Create;
   destructor Destroy; override;
 end;

implementation
uses uPageLoader, uLoadPage, uGlobalVar;

constructor TLoader.Create(FIdHttp := TIdHTTP.Create(nil));
begin
  inherited Create(True);  (*Поток создаем в состоянии «Приостановлен»*)
  FreeOnTerminate := True; (* Поток освободит ресурсы при окончании работы*)  
  Self.Priority := tpNormal;  
end;

destructor TLoader.Destroy;
begin
 FreeAndNil(FIdHttp);
end;

function TLoader.LoadHtmlCode(const Url: String): String;
begin
 Result:=LoadPage(Url, FIdHttp)
end;

procedure TLoader.Execute;
var Code:string;
begin
   Code:=LoadHtmlCode(Url, IdHttp);
     CS.Enter;  (*вход в КС*)
       gStore.Add(Code); (*передаем результат в ГП*)
     Cs.Leave;  (*выход из КС*)
end;

end.
+++++++++++++++другой модуль++++++++++++++++++++
function LoadPage(const Url: String; IdHttp: TIdHttp): String;
begin
Result := AnsiLowerCase(IdHttp.Get(Url))
end;

а вызов потока останется прежний?


 
bems ©   (2012-12-27 21:45) [20]

constructor TLoader.Create(FIdHttp := TIdHTTP.Create(nil));
что это?
в теле конструктора присваивай, там же где FreeOnTerminate := True


 
bems ©   (2012-12-27 21:49) [21]

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


 
Pcrepair ©   (2012-12-27 22:04) [22]

да, это многие советуют - создать пул потоков и давать им задания по закачке страниц. но это следующий этап. пока нужно с этим вариантом разобраться, в частности замечено что на

SSL:=TIdSSLIOHandlerSocketOpenSSL.Create;
Loader.IOHandler:=SSL;

идут исключения в соответствующем модуле ИНДИ.
видимо надо усложнить:

constructor TLoader.Create;
begin
 inherited Create(True);  (*Поток создаем в состоянии «Приостановлен»*)
 FIdHttp := TIdHTTP.Create(nil);

          FSSL := TIdSSLIOHandlerSocketOpenSSL.Create;

 FreeOnTerminate := True; (* Поток освободит ресурсы при окончании работы*)  
 Self.Priority := tpNormal;  
end;


что касается вызова, там ведь тоже есть

ThreadLdr:=Tloader.Create(True); (*создаем поток, но не запускаем*)
   ThreadLdr.Priority:=tpNormal;    (*задать приортет нормальный*)
   ThreadLdr.FreeOnTerminate:=True;  (*самовыгрузка в конце потока*)
      (*передача в поток данных*)
   ThreadLdr.Url:=Url; (*передаем УРЛ в Поток*)
       (*запуск поток на выполнение*)
   ThreadLdr.Start;

получается свой конструктор просто дополняет родительский класс новыми свойствами?
в ООП пока не сильно


 
bems ©   (2012-12-27 22:13) [23]

аа, не, после того как ты добавил конструктор без параметров, вызвать Create(True) уже нельзя

создавай просто ThreadLdr := Tloader.Create; а остальное у тебя уже внутри конструктора


 
Сергей М. ©   (2012-12-27 22:13) [24]


> в ООП пока не сильно


Вот это безобразие

> Create(FIdHttp := чегототам);

в сущности не имеет отношения к ООП


 
Pcrepair ©   (2012-12-27 22:22) [25]


> в сущности не имеет отношения к ООП

ага, разве TThread это не объект? со всеми втекающими и вытекающими

и в чем тут безобразие? поканкратнее пжалуйста


 
bems ©   (2012-12-27 22:32) [26]

в том что это не скомпилируется


 
Сергей М. ©   (2012-12-27 23:00) [27]


> в чем тут безобразие?


см. [26]


 
Pcrepair ©   (2012-12-27 23:16) [28]

не будем спотыкаться об уже пройденное, лучше продолжим:
Сама структура программы в принципе правильная?
- получаем список строк(УРЛ)
- запускаем конвейер потоков, передаем каждому свой УРЛ
- по закачке страницы, поток передает результат в ГлобПерем
- поток самоликвидируется
начинай сначала

получается что в начальный момент может одновременно запуститься практически от 50 до 200 потоков реально
складывается впечетление(по ошибке 10038 и 10056) что где то есть узкое место, всем потокам не хватает трафика и некоторые получают отказ. непонятно только как, временные интервалы в idHTTP для подключения к серверу и работы с сервером установлены в 50 сек.

или есть решения поумнее?


 
Сергей М. ©   (2012-12-27 23:19) [29]


> есть решения поумнее?


Объясни накой тебе аж 50 и более потоков ?


 
bems ©   (2012-12-27 23:31) [30]


> в начальный момент может одновременно запуститься практически
> от 50 до 200 потоков

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


> реально
> складывается впечетление(по ошибке 10038 и 10056) что где
> то есть узкое место, всем потокам не хватает трафика и некоторые
> получают отказ

в варианте без общего использования одного idHttp ошибки остаются?


 
Pcrepair ©   (2012-12-27 23:31) [31]

для полного использования трафика. в среднем скорость выдачи у серверов небольшая. если трафик к примеру 5000 кбит\сек, при средней скорости отдачи серверов 50 кбит\сек можно запускать до 100 потоков одновременно, ну чтоб провыдЫр не за так деньги получал


 
Pcrepair ©   (2012-12-27 23:36) [32]


> в варианте без общего использования одного idHttp ошибки
> остаются?

этот вариант еще не попробовал и вот почему: на самом деле функция в 19

+++++++++++++++другой модуль++++++++++++++++++++
function LoadPage(const Url: String; IdHttp: TIdHttp): String;
begin
 Result := AnsiLowerCase(IdHttp.Get(Url))
end;

IdHttp не содержит. LoadPage состоит из нескольких функций

unit uPageLoader;
interface
uses Classes, SysUtils, idHTTP, StrUtils, IdSSL, IdSSLOpenSSL;
   function LoadPage(const Url:string):string;  (*Основная функция Юнита*)
   procedure ErrorLog(Url:string);
   function LoadHtmlPage(const PageUrl:string):string;
   function DelJS(const Code:string):string;
   function RestoreFrame(const Code:string):string;
   function RestoreFullUrl(const Code:string; const RootUrl:string):string;
   function GetRandomUserAgent: string;
   var
   Loader:TidHTTP;
   SSL:TIdSSLIOHandlerSocketOpenSSL;

в том числе function LoadHtmlPage(const PageUrl:string):string; в которой как и есть idHTTP
Пока не совсем понятно как вызывать свой экземпляр idHTTP и SSL
Никаких идей нет?


 
Сергей М. ©   (2012-12-27 23:43) [33]


> чтоб провыдЫр не за так деньги получал


О как сурово)


 
bems ©   (2012-12-27 23:49) [34]

передавай через параметр как и в LoadPage.
ssl на момент вызова уже по идее должен быть присвоен в iohandler, поэтому ssl вообще можно убрать


 
Pcrepair ©   (2012-12-28 00:04) [35]


> ssl на момент вызова уже по идее должен быть присвоен в
> iohandler, поэтому ssl вообще можно убрать

некоторые утверждают что SSL:TIdSSLIOHandlerSocketOpenSSL; тоже получается как и idHTTP общее для всех потоков. и при отладке выскакивают исключения, которые указывают на модуль IdSSLOpenSSL(смотри[8])

в общем прийдется модуль переписать, под многопоточность


 
Pcrepair ©   (2012-12-28 00:05) [36]

а может попробовать в качестве загрузчика ICS


 
bems ©   (2012-12-28 00:11) [37]


> некоторые утверждают что SSL:TIdSSLIOHandlerSocketOpenSSL;
>  тоже получается как и idHTTP общее для всех потоков. и
> при отладке выскакивают исключения, которые указывают на
> модуль IdSSLOpenSSL

общий, но ты ж добавил в конструктор треда FSSL := TIdSSLIOHandlerSocketOpenSSL.Create;
вот остальные ssl убирай, и присваивай FidHttp.IoHandler еще перед вызовом LoadPage
ну и в uPageLoader передавай IdHttp везде через параметр


 
Германн ©   (2012-12-28 01:44) [38]


> Pcrepair ©   (28.12.12 00:05) [36]
>
> а может попробовать в качестве загрузчика ICS

Попытка - не пытка. Попробуй.
Лично я предпочитаю всегда ICS. Но я не занимался разработкой "поисковой машины". Так что мне больше нечего сказать.


 
Pcrepair ©   (2012-12-28 16:30) [39]

ну раз ты предпочитаешь ICS, тогда поведай миру о своем опыте, конкретно, есть ли в ICS:
- встроенная обработка перенаправления 301 и 302
- правильная кодировка кирилицы(так называемые кракрзябры вместо правльных букаф)
- возможность закачки HTTPs
- возможность установки нужного значения юзер-агент
- управление временем подключения к серверу и работы с сервером. ограничение в смысле

как видишь, если у тебя есть опыт работы, сказать много что вполне возможно
можно и примерный код выставить, или хотя бы дать ссылки
ждемс


 
Pcrepair ©   (2012-12-28 19:22) [40]

а если вот так:

type
 TLoader = class(TThread) (*создаем свой класс на базе ПОТОК*)
 private
    FUrl:string; (*поле класса типа СТРОКА для чтения -записи данных*)
    FIdHttp:TidHTTP;
    FSSL:TIdSSLIOHandlerSocketOpenSSL;
 protected
   procedure Execute; override;
   function LoadHtmlCode(const Url: String):string; (*ФУНК загрузки страницы*)
 public
   property Url: string read FUrl write FUrl;  (*свойство класа, доступное для всей программы*)
   constructor Create;
   destructor Destroy; override;
 end;

implementation
uses Unit1, uLoadPage, uGlobalVar;

constructor TLoader.Create;
begin
 inherited Create(True); (*Поток создаем в состоянии «Приостановлен»*)
 FIdHttp := TIdHTTP.Create(nil);
 FSSL := TIdSSLIOHandlerSocketOpenSSL.Create;
 FreeOnTerminate := True; (* Поток освободит ресурсы при окончании работы*)
 Self.Priority := tpNormal;
end;

destructor TLoader.Destroy;
begin
 FreeAndNil(FIdHttp);
 FreeAndNil(FSSl);
end;

(*  28.12.2012 функция загрузки страницы прямо в коде потока*)
function TLoader.LoadHtmlCode(const Url: String):string;
begin
 FIdHttp.IOHandler:=FSSL;
 FIdHttp.HandleRedirects:=True;
 Result:=FIdHttp.Get(Url);
end;

procedure TLoader.Execute;
var Code:string;
begin
   Code:=LoadHtmlCode(Url);
     begin
      CS.Enter;  (*вход в КС*)
        try
          gStore.Add(Code); (*передаем результат в ГП*)
        finally
     Cs.Leave;  (*выход из КС*)
    end;
 end;
end;

end.

то есть функция загрузки с idHTTP прямо в потоке. потом тут же дописать обертку (небольшой цикл по закачке фреймов) а функции обработки кода страницы вообще вызывать в поток из другого модуля
или еще лучще тут их написать но не как метод потока а сверху так сказать. или все же лучше сделать все функции методами класса??


 
Сергей М. ©   (2012-12-28 20:05) [41]


> constructor TLoader.Create;
> ..
>  Self.Priority := tpNormal; // эта строчка гуляет по Тырнету в миллионах экз-рах, ты ее позорно сдул  - и какое отношение к себе при этом ты изволишь желать ?
>..
> end;


 
Pcrepair ©   (2012-12-28 21:02) [42]

Удалено модератором


 
Pcrepair ©   (2012-12-28 21:45) [43]

Удалено модератором
Примечание: Правила форума надо уважать


 
Германн ©   (2012-12-29 02:30) [44]

Удалено модератором


 
Pcrepair ©   (2012-12-29 20:56) [45]

ну что все уже празднуют? вопросы еще остались

сделал все функции и процедуры методами класса, из доп модулей ничего не вызывается
ошибки остались, только для этих страниц:
----------------это все из отладчика----------------------------------------
IdHTTP.TIdCustomHTTP.Get("http://www.xard.ru/post/10305/",(...))
IdHTTP.TIdCustomHTTP.Get("http://www.electrosad.ru/Electronics/PP.htm",$16D3A00,(...))
uThreadLoader.TLoader.LoadHtmlCode("http://www.xard.ru/post/10305/")

для всех пишет одно и то же(в режиме отладки):
First chance exception at $7C812AFB. Exception class EConvertError with message """"" is not a valid integer value". Process Project.exe (2728)
Что это непонятно, так как страницы закачиваются

в остальном все хорошо, утечки памяти нет, закачиваются все страницы


 
Медвежонок Пятачок ©   (2012-12-29 21:11) [46]

Что что. Это твоя обработка текста страницы. К загрузке отношения не имеющая.


 
Pcrepair ©   (2012-12-29 21:18) [47]

нет в IdHTTP.TIdCustomHTTP.Get никакой обработки.


 
Медвежонок Пятачок ©   (2012-12-29 21:23) [48]

А кто тогда делает  strtoint? Дедушко мороз?


 
Медвежонок Пятачок ©   (2012-12-29 21:30) [49]

А кто тогда делает  strtoint? Дедушко мороз?


 
Pcrepair ©   (2012-12-29 22:30) [50]

это ты так очень иносказательно, почти как дедушко Крылов, намекаешь что исключение связано с использованием системной функции?

кстати, нет там нигде StrToInt. и IntToStr то же нет


 
Медвежонок Пятачок ©   (2012-12-29 22:36) [51]

ну значит и эксепшена нет. Наверное тебе привиделось.


 
Сергей М. ©   (2012-12-29 22:41) [52]


> Что это непонятно


Это практически наверняка результат по-прежнему отсутствующей синхронизации обращения твоей дивизии потоков к какому-то общему ресурсу.


 
Pcrepair ©   (2012-12-29 22:52) [53]

да уже второй день как есть синхронизация, всего к всему
это фигня вылезает на 2-х страницах, всегда одних и тех же, из 200 в списке

кстати, повторюсь, страницы все равно закачиваются, те самые на кторых выскакивает исключение (в режиме отладки только)


 
Сергей М. ©   (2012-12-29 22:59) [54]

Если однопоточная загрузка (о чем тебе еще в [4] намекнул Вася) этих страниц не вызывает исключения, можешь смело забить на него.
В противном случае ССЗБ.


 
Игорь Шевченко ©   (2012-12-29 23:12) [55]

Pcrepair ©   (29.12.12 20:56) [45]

> для всех пишет одно и то же(в режиме отладки):
> First chance exception at $7C812AFB. Exception class EConvertError
> with message """"" is not a valid integer value". Process
> Project.exe (2728)
> Что это непонятно


Наверное в режиме отладки и строки, на которых проиходит исключение, показываются.

Не томи.


 
DVM ©   (2012-12-29 23:26) [56]


> Pcrepair ©   (28.12.12 19:22) [40]


>  public
>    property Url: string read FUrl write FUrl;  (*свойство
> класа, доступное для всей программы*)

это свойство не потокобезопасно, к нему есть обращения одновременно на изменение и чтение из разных потоков?


 
DVM ©   (2012-12-29 23:28) [57]


> Pcrepair ©   (29.12.12 22:52) [53]
> да уже второй день как есть синхронизация, всего к всему

Да ладно, не верю. Более чем уверен, что вот к этому твоему gStore есть не защищенные обращения.


 
Pcrepair ©   (2012-12-30 22:21) [58]

Игорь Шевченко

> Наверное в режиме отладки и строки, на которых проиходит
> исключение, показываются.

SysUtils

procedure ConvertErrorFmt(ResString: PResStringRec; const Args: array of const); local;
begin
 raise EConvertError.CreateResFmt(ResString, Args); (*тут*)
end;


Call stack -THread 4064

:7c812afb kernel32.RaiseException + 0x52
System.SysUtils.ConvertErrorFmt($4129A8,(...))
System.SysUtils.StrToInt("")
IdGlobal.IndyStrToInt("")
IdGlobalProtocols.RawStrInternetToDateTime("",0)
IdGlobalProtocols.GMTToLocalDateTime("")
IdHTTPHeaderInfo.TIdEntityHeaderInfo.ProcessHeaders
IdHTTPHeaderInfo.TIdResponseHeaderInfo.ProcessHeaders
IdHTTP.TIdHTTPProtocol.RetrieveHeaders(???)
IdHTTP.TIdCustomHTTP.DoRequest(???,"http://www.xard.ru/post/10305/",nil,$16D3B20,(...))
IdHTTP.TIdCustomHTTP.Get("http://www.xard.ru/post/10305/",$16D3B20,(...))
IdHTTP.TIdCustomHTTP.Get("http://www.xard.ru/post/10305/",(...))
IdHTTP.TIdCustomHTTP.Get("http://www.xard.ru/post/10305/")
uThreadLoader.TLoader.LoadHtmlCode("http://www.xard.ru/post/10305/")
uThreadLoader.TLoader.LoadPage("http://www.xard.ru/post/10305/")
uThreadLoader.TLoader.Execute
System.Classes.ThreadProc($16FE0A0)
System.ThreadWrapper($16E13E0)
:7c80b729 ; C:\WINDOWS\system32\kernel32.dll

причем на каждом УРЛ исключение выскакивает дважды
++++++++++++++++++++++++++++++++++++++++++++++++++

> это свойство не потокобезопасно, к нему есть обращения одновременно
> на изменение и чтение из разных потоков?

вообще то через это свойство в поток передается УРЛ, как оно не может быть public? потом значение из этого поля идет в поток и тд...
в конвейре запуска потоков, каждому потоку передается свое значение, после чего поток его обрабатывает. это все
---------------
к gStore любые обращения идут через CS, это не сложно


 
DVM ©   (2012-12-30 22:36) [59]


> Pcrepair ©   (30.12.12 22:21) [58]


> вообще то через это свойство в поток передается УРЛ, как
> оно не может быть public?

А кто говорил, что оно не может быть паблик? На здоровье пусть будет паблик, но оно не потокобезопасно. Сделать потокобезопасное свойство не проблема если что.


> к gStore любые обращения идут через CS, это не сложно

Ну как сказать, везде ли у тебя при любом обращении к любому свойству, любому методу этого gStore сначала происходит вход в крит секцию а потом выход? Это не всегда очевидно.


 
Pcrepair ©   (2012-12-30 22:40) [60]

и вот еще что, это исключение есть даже при самом простом коде закачки. один к одному. без всяких потоков. без gStore. без всего

unit uPageLoader;
interface
uses idHTTP, SysUtils;
 function LoadPage(const Url:string):string;
 var idHttp:TidHTTP;
implementation

function LoadPage(const Url:string):string;
begin
 idHttp:=TidHttp.Create(nil);
    Result:=idHttp.Get(Url);
 FreeAndNil(idHttp);
end;
end.


похоже это косяк ИНДИ


 
bems ©   (2012-12-30 22:42) [61]

ну похоже что по этим адресам в хидерах где-то позвращается пустая дата.
посмотри попадает ли этот эксцепшн в твой обработчик. если нет, то это внутренние дела indy

в версии индейцев которая идет с дельфи XE2 я вижу что в случае эксцепшна в RawStrInternetToDateTime она просто возвращает false и считает жксцепшн обработанным. Правда в ней же в самом начала стоит проверка не передана ли в RawStrInternetToDateTime пустая строка, и в этом случае возвращается false без возникновения эксцепшна. но может оказаться что эту проверку добавили позже и в твоей версии ее еще нет.

в общем если индейцы сами обрабатывают это исключение то беспокоиться не нужно


 
DVM ©   (2012-12-30 22:46) [62]


> Pcrepair ©   (30.12.12 22:40) [60]


> вот еще что, это исключение есть даже при самом простом
> коде закачки. один к одному.

ну возникает исключение и что? не вижу повода для паники. У тебя этих исключений может возникнуть вагон и маленькая тележка, начиная от недоступности сайта, заканчивая некорректными HTTP заголовками и пр, на что инди вполне закономерно выбрасывает исключения. Если какие то типы исключений нельзя пропускать наружу, try...except тебе в помощь, желательно с логгированием.


 
DVM ©   (2012-12-30 22:46) [63]


> Pcrepair ©   (30.12.12 22:40) [60]


> вот еще что, это исключение есть даже при самом простом
> коде закачки. один к одному.

ну возникает исключение и что? не вижу повода для паники. У тебя этих исключений может возникнуть вагон и маленькая тележка, начиная от недоступности сайта, заканчивая некорректными HTTP заголовками и пр, на что инди вполне закономерно выбрасывает исключения. Если какие то типы исключений нельзя пропускать наружу, try...except тебе в помощь, желательно с логгированием.


 
Pcrepair ©   (2012-12-30 22:51) [64]


> посмотри попадает ли этот эксцепшн в твой обработчик. если
> нет, то это внутренние дела indy

что бы это значило? это исключение видно только в режиме отладки, если запустить откомп. приложение то никаких сообщений не появляется,  все работает как предначертано

в ХЕ2 ИНДИ был очень кривой, из за его косяков при загрузке страниц пробовал даже перейти на другие варианты(ICS и прочее)
сейчас пробую ХЕ3 инди 10.5.9.0 - значительно лучше, выбор кодировки даже почти работает (80% случаев). 302 и 301 тоже работают, но видимо до ума еще доводить и доводить


 
Pcrepair ©   (2012-12-30 22:55) [65]

DVM

> Сделать потокобезопасное свойство не проблема если что.

расскажи лучше об этом поподробнее.
сейчас так:

type
 TLoader = class(TThread) (*создаем свой класс на базе ПОТОК*)
 private
    FUrl:string; (*поле класса типа СТРОКА для чтения -записи данных*)
    FIdHttp:TidHTTP;
    FSSL:TIdSSLIOHandlerSocketOpenSSL;
 protected
   procedure Execute; override;
   function LoadHtmlCode(const PageUrl: String):string; (*ФУНК загрузки страницы*)
   procedure ErrorLog(Url:string);
   function GetRandomUserAgent: string;
   function LoadPage(const Url:string):string;
   function DelJS(const Code:string):string;
   function RestoreFrame(const Code:string):string;
   function RestoreFullUrl(const Code:string; const RootUrl:string):string;
   function CorrectUrl(const UrlStr:string):string;
 public
   property Url: string read FUrl write FUrl;  (*свойство класа, доступное для всей программы*)
   constructor Create;
   destructor Destroy; override;
 end;

а раньше вообще

public
   var Url: string;  (*свойство класа, доступное для всей программы*)
   constructor Create;
   destructor Destroy; override;
 end;

и вроде все работало
твой вариант:


 
bems ©   (2012-12-30 22:56) [66]


> что бы это значило?

что indy обрабатывает это исключение, значит не косяк (хотя могли бы и без эксцепшна проверить).
ну или ты его сам глушишь, проверь что это не так


 
DVM ©   (2012-12-30 22:57) [67]


> Pcrepair ©   (30.12.12 22:51) [64]


> в ХЕ2 ИНДИ был очень кривой, из за его косяков при загрузке
> страниц пробовал даже перейти на другие варианты(ICS и прочее)

Ну и что же не перешел? Ты извини, но твоя квалификация недостаточна, для объективной оценки качества работы Indy. Indy библиотека, до которой многим другим еще расти и расти.


> выбор кодировки даже почти работает (80% случаев).

какое отношение TIdHTTP имеет к каким либо кодировкам? Это вообще не его дело.


> 302 и 301 тоже работают, но видимо до ума еще доводить и
> доводить

Нет там никаких проблем, и не было, по крайней мере у меня.


 
DVM ©   (2012-12-30 23:07) [68]


> Pcrepair ©   (30.12.12 22:55) [65]
> DVM
>
> > Сделать потокобезопасное свойство не проблема если что.
>
>
> расскажи лучше об этом поподробнее.

TMyClass = class
private
 FCS: TCriticalSection;
 FMyProp: string;
 function GetMyProp: string;
 procedure SetMyProp(const AValue: string);
public
 property MyProp: string read GetMyProp write SetMyProp;
 ..

function TMyClass.GetMyProp: string;
begin
 FCS.Enter;
 try
   Result := FMyProp;
 finally
   FCS.Leave;
 end;
end;

function TMyClass.SetMyProp(const AValue: string);
begin
 FCS.Enter;
 try
   FMyProp := AValue;
 finally
   FCS.Leave;
 end;
end;


И ГЛАВНОЕ!!! Во всех методах самого TMyClass обращаться исключительно к MyProp, но не FMyProp!!!


 
DVM ©   (2012-12-30 23:08) [69]


> Pcrepair ©   (30.12.12 22:55) [65]

и еще, описанный мной способ не прокатит для сложных свойств, представляющих собой классы и т.д., в них должны быть свои потокозащищенные поля.


 
bems ©   (2012-12-30 23:19) [70]

поковырялся
по адресу "http://www.electrosad.ru/Electronics/PP.htm" (или какому-то куда он редиректит) в заголовке "Expires" возвращается "24.02.2012"
Инди ожидают увидеть в этой строкен в качестве разделителя даты либо "-" (и называют это поддержкой бажных серверов) либо пробел. Точку там они не ожидают, поэтому у них возникает эксцепшн. В качестве обработки они считают что указана дата 30.12.1899.
Наружу, как и ожидалось, этот эксцепшн не попадает


 
Pcrepair ©   (2012-12-30 23:22) [71]

может тогда уже использовать TMultiReadExclusiveWriteSynchronizer? чем писать свои реализации чтение-запись?
----------------------------
может ИНДИ(из комплекта ХЕ2) и огого, но вот спотыкалась при загрузке некоторых страниц, причем так спотыкалась что даже полное подавление исключений не помогло - программа(простейший код) просто зависала и все. а в РАД2010 и ХЕ3 тот же самый код работает нормально.
что касается кодовой страницы: в РАД2010 - кракозябры, в ХЕ3 - кырилица в норме( в 80%) случаев. так что выводы сделать можно и без огромного опыта


 
DVM ©   (2012-12-30 23:23) [72]


> bems ©   (30.12.12 23:19) [70]


> в заголовке "Expires" возвращается "24.02.2012"

Так вроде не по стандарту же. Должно быть типа
Expires: Tue, 31 Jan 2012 15:02:53 GMT
возмущение Indy резонно.


 
DVM ©   (2012-12-30 23:25) [73]


> Pcrepair ©   (30.12.12 23:22) [71]
> может тогда уже использовать TMultiReadExclusiveWriteSynchronizer?
>  чем писать свои реализации чтение-запись?

с TMultiReadExclusiveWriteSynchronizer придется писать ровно то же что и с крит секцией.


 
DVM ©   (2012-12-30 23:30) [74]


> Pcrepair ©   (30.12.12 23:22) [71]


> может ИНДИ(из комплекта ХЕ2) и огого, но вот спотыкалась
> при загрузке некоторых страниц, причем так спотыкалась что
> даже полное подавление исключений не помогло - программа(простейший
> код) просто зависала и все. а в РАД2010 и ХЕ3 тот же самый
> код работает нормально.

И что там в исключениях написано было?


> что касается кодовой страницы: в РАД2010 - кракозябры, в
> ХЕ3 - кырилица в норме( в 80%) случаев. так что выводы сделать
> можно и без огромного опыта

Еще раз повторю, TIdHTTP не имеет никакого отношения к кодировкам. То, что у метода Get есть вариант возвращающий строку, это еще не значит что он обязан за тебя делать перекодировку. И вообще, надо использовать вариант с Get где TStream в параметрах, получать кодировку документа и перекодировать полученные данные.


 
bems ©   (2012-12-30 23:30) [75]


> Так вроде не по стандарту же.

я ж как чукча, что вижу о том и пою. И не говорю что это должно корректно обрабатываться


> возмущение Indy резонно.

они даже и не возмущаются, просто присваивают дате нулевое значение. но могли бы вместо кидания-обработки исключения и TryStrToInt делать


 
Pcrepair ©   (2012-12-30 23:37) [76]

а исключений не было. программа просто зависала и все. что в режиме отладки что откомпилилированная.

и еще раз повторю: похоже инди 10.5.9.0 УЖЕ имеет отношение к выбору кодировки страницы - видимо встроили. вот если использовать Tmemory.Stream для вывода кода закачанной страницы(idHttp>Get(Url, Stream), там действительно кракозябры вместо кырилицы, поскольку поток выводит код в первозданном виде. а если idHttp.Get(Url), кырилицы в норме(имеется ввиду закачка одной и той же страницы). у меня во всяком случае так. специально проверял


 
DVM ©   (2012-12-30 23:41) [77]


> Pcrepair ©   (30.12.12 23:37) [76]


> вот если использовать Tmemory.Stream для вывода кода закачанной
> страницы(idHttp>Get(Url, Stream), там действительно кракозябры
> вместо кырилицы, поскольку поток выводит код в первозданном
> виде

Вот именно, что в первозданном, если эту страницу надо сохранить где то, то ее в этом первозданном виде и надо сохранять, а до кучи и хидеры HTTP к ней. А перед использованием приводить к читабельному виду с помощью TStringStream с указанием кодировки например. По крайней мере так ничего не теряется от оригинала.


 
DVM ©   (2012-12-30 23:41) [78]


> Pcrepair ©   (30.12.12 23:37) [76]


> вот если использовать Tmemory.Stream для вывода кода закачанной
> страницы(idHttp>Get(Url, Stream), там действительно кракозябры
> вместо кырилицы, поскольку поток выводит код в первозданном
> виде

Вот именно, что в первозданном, если эту страницу надо сохранить где то, то ее в этом первозданном виде и надо сохранять, а до кучи и хидеры HTTP к ней. А перед использованием приводить к читабельному виду с помощью TStringStream с указанием кодировки например. По крайней мере так ничего не теряется от оригинала.


 
Pcrepair ©   (2012-12-30 23:48) [79]

и какую же кодировку указать? ту что в заголовке страницы, или ту что получена от сервера? оне часто не совпадают


 
DVM ©   (2012-12-30 23:55) [80]


> Pcrepair ©   (30.12.12 23:48) [79]


> и какую же кодировку указать?


> оне часто не совпадают

Более того они обе могут быть и неправильными. А ты от Indy хочешь чтоб она правильно перекодировала.

Вообще сначала надо смотреть кодировку страницы и если она не указана то брать кодировку сервера


 
DVM ©   (2012-12-30 23:58) [81]


>
> > Pcrepair ©   (30.12.12 23:48) [79]

и Indy не парсит HTML  - это не его дело, кодировку он оттуда не достает по любому!!!


 
Pcrepair ©   (2012-12-31 00:05) [82]

значит берет из ответа сервера, отсюда и бывают иногда кракозябры, когда кодировка указанная в коде страницы не сооответствут данным от сервера.
но перекодировку ИНДИ 10.5.9.0 точно делает
это видно. если один и тот же код загрузчика откомпилировать в РАД2010 и ХЕ3 то одна и та же страница(1251) в одном случае кракозябры(рад2010) в другом правильная кодировка


 
Styx   (2012-12-31 00:09) [83]

Это ещё не показатель... Возможно, у них запросы отличаются, а сервер в ответ на эти разные запросы отдаёт контент в разной кодировке...


 
DVM ©   (2012-12-31 00:13) [84]


> Pcrepair ©   (31.12.12 00:05) [82]


> но перекодировку ИНДИ 10.5.9.0 точно делает

Да и не отрицаю нигде этого. Я говорю, что на это полагаться нельзя, т.к. Indy в отличие от тебя не парсит HTML, а ты парсишь, так не лучше ли самому с кодировкой определяться? Надежнее по любому.


 
DVM ©   (2012-12-31 00:13) [85]


> Pcrepair ©   (31.12.12 00:05) [82]


> но перекодировку ИНДИ 10.5.9.0 точно делает

Да и не отрицаю нигде этого. Я говорю, что на это полагаться нельзя, т.к. Indy в отличие от тебя не парсит HTML, а ты парсишь, так не лучше ли самому с кодировкой определяться? Надежнее по любому.


 
bems ©   (2012-12-31 00:17) [86]

DVM, почему IdHttp должен игнорировать кодировку? http это не текстовый протокол же. и как пользовательский код должен отличать скажем UTF-16BE от UTF-16LE, если с ними двумя даже нельзя нормально прочитать что там указано для кодировки в html-коде


 
Pcrepair ©   (2012-12-31 00:18) [87]


> так не лучше ли самому с кодировкой определяться? Надежнее
> по любому.

ну это не простой вопрос. даже Mlang, а там наворочено куча доп. модулей и то не всегда точно определяет(лично пробовал). так что приходтся идти на компромис: приемлемый результат - время затраты на решение возможно не решаемой задачи.
критерия то выбора способа перекодировки 100% достоверного нет


 
bems ©   (2012-12-31 00:20) [88]


> http это не текстовый протокол же

ну вы поняли ,что я имел в виду


 
DVM ©   (2012-12-31 00:30) [89]


> bems ©   (31.12.12 00:17) [86]
> DVM, почему IdHttp должен игнорировать кодировку?

а почему он собственно должен?


> http это не текстовый протокол же

Ну он и есть не текстовый, текстовые у него только хидеры. Непонятно, почему для типа контента текст должно делаться исключение и он должен перекодироваться в удобный пользователю вид? Почему он тогда сам картинки Jpeg не декодирует. Почему он видео не показывает?  и т.д.


> и как пользовательский код должен отличать скажем UTF-16BE
> от UTF-16LE, если с ними двумя даже нельзя нормально прочитать
> что там указано для кодировки в html-коде
>
>

там должен быть BOM


 
bems ©   (2012-12-31 00:42) [90]


> Непонятно, почему для типа контента текст должно делаться
> исключение и он должен перекодироваться в удобный пользователю
> вид?
ну потому что метод Get возвращает тело ответа, и не возвращает хидеры (я говорю про ту версию что без стрима). соответственно этот метод должен возвращать тело в виде с которым можно работать


> там должен быть BOM
он только для UTF-16, а при UTF-16BE и UTF-16LE BOM искать нельзя
да и в случае UTF-16 пользователь должен знать что там двухбайтный символ, чтобы сделать вывод что нельзя просто читать подмножество ascii которое везде одинаково
вариант метода возвращающий данные в стриме не должен перекодировать, тут я согласен


 
DVM ©   (2012-12-31 00:48) [91]


> bems ©   (31.12.12 00:42) [90]


> ну потому что метод Get возвращает тело ответа, и не возвращает
> хидеры (я говорю про ту версию что без стрима).

ну хидеры то у нас всегда есть, аж два раза один рас в событии TidHTTP до загрузки, второй раз, в объекте Response.


> соответственно этот метод должен возвращать тело в виде
> с которым можно работать

Но это невозможно на 100%, не разбирая HTML, сам же понимаешь.
Этот метод он для элементарных случаев.

Кстати, кто-то хоть раз видел сайт со страницами в кодировках UTF16?


> он только для UTF-16, а при UTF-16BE и UTF-16LE BOM искать
> нельзя

КАК ТАК?

UTF-8
EF BB BF
UTF-16BE
FE FF
UTF-16LE
FF FE
UTF-32BE
00 00 FE FF
UTF-32LE
FF FE 00 00


 
DVM ©   (2012-12-31 00:52) [92]


> bems ©

я не понимаю, в чем проблема определения кодировки если есть BOM? Если BOM нет, то кодировка должна быть такой, чтобы само название кодировки хотя бы можно было прочитать, если же и это не соблюдается, то тут уж не поможет ничто и настолько криворуко сделанный сайт проще игнорировать.


 
bems ©   (2012-12-31 00:53) [93]


> Но это невозможно на 100%, не разбирая HTML, сам же понимаешь.
я имею в виду только анализ хидеров. потому что без него нельзя начать и разбор html


> КАК ТАК?
а вот так. rfc 2781:
  Text labelled "UTF-16BE" can always be interpreted as being big-
  endian.  The detection of an initial BOM does not affect de-
  serialization of text labelled as UTF-16BE. Finding 0xFF followed by
  0xFE is an error since there is no Unicode character 0xFFFE.

если порядок байт указан явно, то первые байты должны считаться первым символом текста, даже когда олни похожи на BOM


 
Styx   (2012-12-31 00:56) [94]

Какой BOM, Вы о чём тут вообще? Хоть один сайт отдаёт BOM??? Я попробовал в UTF-8 отдавать - так половина браузеров мне его в виде квадратика рисовало...


 
bems ©   (2012-12-31 00:57) [95]

мы тут о стандартах, если я правильно понимаю нить разговора


 
DVM ©   (2012-12-31 00:59) [96]


> bems ©   (31.12.12 00:53) [93]
>

в любом случае есть статистические методы определения кодировки, и уж точно Indy их не станет использовать. Это задача клиентского приложения.


 
bems ©   (2012-12-31 01:05) [97]

полной правильной перекодировки я и не жду от него. но если в хидере указано что это UTF-16BE, и если тип String, в котором юзер получает тело ответа состоит из двухбайтовых символов, то я думаю юзер в праве ожидать что порядок байт в widechar"e будет соответствовать тому что используется в типе string а не тому что получено от сервера


 
DVM ©   (2012-12-31 01:05) [98]


> Styx   (31.12.12 00:56) [94]
> Какой BOM, Вы о чём тут вообще? Хоть один сайт отдаёт BOM?
> ?? Я попробовал в UTF-8 отдавать - так половина браузеров
> мне его в виде квадратика рисовало...

насколько я понимаю, браузеры прибегают к поиску BOM в последнем случае, если иными методами определить кодировку не удалось, большинство сайтов отдают кодировку так как положено в заголовка HTTP и HTML


 
DVM ©   (2012-12-31 01:07) [99]


> bems ©   (31.12.12 01:05) [97]
> полной правильной перекодировки я и не жду от него. но если
> в хидере указано что это UTF-16BE, и если тип String, в
> котором юзер получает тело ответа состоит из двухбайтовых
> символов, то я думаю юзер в праве ожидать что порядок байт
> в widechar"e будет соответствовать тому что используется
> в типе string а не тому что получено от сервера

Ну так оно сейчас так и есть, но только если с HTTP хидером все в порядке и кодировка страницы действительно такая как в хидере указано.


 
DVM ©   (2012-12-31 01:07) [100]


> bems ©   (31.12.12 01:05) [97]
> полной правильной перекодировки я и не жду от него. но если
> в хидере указано что это UTF-16BE, и если тип String, в
> котором юзер получает тело ответа состоит из двухбайтовых
> символов, то я думаю юзер в праве ожидать что порядок байт
> в widechar"e будет соответствовать тому что используется
> в типе string а не тому что получено от сервера

Ну так оно сейчас так и есть, но только если с HTTP хидером все в порядке и кодировка страницы действительно такая как в хидере указано.



Страницы: 1 2 3 вся ветка

Форум: "Начинающим";
Текущий архив: 2013.09.15;
Скачать: [xml.tar.bz2];

Наверх





Память: 0.81 MB
Время: 0.004 c
15-1365199357
Дмитрий С
2013-04-06 02:02
2013.09.15
Переменные окружения и COM объект.


2-1357388251
Евгений07
2013-01-05 16:17
2013.09.15
исчезает Image при простых действиях


15-1365407634
xayam
2013-04-08 11:53
2013.09.15
Мелодия


2-1357291115
Pcrepair
2013-01-04 13:18
2013.09.15
Проблемы с передачей параметров в поток через TStringList


15-1365005875
О-Сознание
2013-04-03 20:17
2013.09.15
Надёжность GetWindowLong(H, GWL_USERDATA)





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский