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

Вниз

Обработка исключений Indy   Найти похожие ветки 

 
Nilman ©   (2009-08-27 18:00) [0]

Помогите пож правильно обработать неудачные попытки соединения в Indy. Есть функция, которая проверяет доступность сервиса, к которому планируется дальнейшее обращение:

function NetAvail:boolean;
var
 HTTP: TIdHTTP;
 FServAnsw: WideString;
 IdProxyConnectionInfo: TIdProxyConnectionInfo;
begin
 Result:=False;
 HTTP:=TIdHTTP.Create(MainForm);
 IdProxyConnectionInfo:=TIdProxyConnectionInfo.Create;
 try
   HTTP.ReadTimeout:=30000;

   if MainForm.AppSettings.UseProxy then
   begin
     IdProxyConnectionInfo.ProxyServer:=MainForm.AppSettings.ProxyHost;
     IdProxyConnectionInfo.ProxyPort:=StrToInt(MainForm.AppSettings.ProxyPort);
     IdProxyConnectionInfo.ProxyUsername:=MainForm.AppSettings.ProxyLogin;
     IdProxyConnectionInfo.ProxyPassword:=MainForm.AppSettings.ProxyPassw;
     HTTP.ProxyParams:=IdProxyConnectionInfo;
   end;
   try
     FServAnsw:=Http.Get("http://"+MHost+"/isavail.txt");
   except
     on e: Exception do
       begin
         //ShowMessage(e.Message);
       end;
   end;
 finally
   HTTP.Free;
   IdProxyConnectionInfo.Free;
 end;

 if Pos(UnicodeString("ok"),UnicodeString(FServAnsw))>0 then Result:=True;
end;

...........................

 while not NetAvail do
 begin
   Synchronize(VCL_ShowNoInetMsg);
   if InfoForm.ModalResult<>mrOK then Terminate;
 end;

Когда не использую прокси, но хост недоступен, всё проходит нормально, выдаётся сообщение проверить интернет или повторить позднее. При использовании рабочего прокси, тоже всё вроде ровно. Когда подставляю заведомо нерабочий прокси, получаю сначала ошибку 10061 от сокета, которую могу контролировать, потом вылетает Invalid pointer operation. Судя по всему летит оно откуда то из недр инди, т.к. вылетает она на строке Http.Get... Подскажите пож, это ошибка инди или же я её как то неправильно ловлю?.. И вообще бывают ли не обрабатываемые исключения, которые нельзя по тихому обработать и не пугать юзера?


 
Сергей М. ©   (2009-08-27 20:11) [1]


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


Можно подумать, что при "дальнейшем обращении" ранее проверенный на доступность сервис просто обязан быть доступным..


> это ошибка инди


Хрен с ним, с Инди ..

Смущает другое - Syncronize() и следом же несинхронизированное образение к VCL-объекту ..

Что еще за чудеса у тебя там творятся в доп.потоке - пока известно тебе лишь одному)


 
Nilman ©   (2009-08-28 20:37) [2]


> Можно подумать, что при "дальнейшем обращении" ранее проверенный
> на доступность сервис просто обязан быть доступным..

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

> Смущает другое - Syncronize() и следом же несинхронизированное
> образение к VCL-объекту ..

а зачем синхронизация при чтении значения свойства окна?.. и вообще эта строчка там собсно не нужна, считаем что её там нет

> Что еще за чудеса у тебя там творятся в доп.потоке - пока
> известно тебе лишь одному)

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

procedure TRegisterThread.VCL_ShowNoInetMsg;
begin
   if InfoForm.ShowRetryCancelInfo("You are need an active Internet connection to continue registration. Connect to the Internet and click Retry.")<>mrOK then
   begin
     Success:=False;
     Terminate;
     Exit;
   end;
end


 
Сергей М. ©   (2009-08-28 22:13) [3]


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


С чего бы вдруг считаем ?


> зачем синхронизация при чтении значения свойства окна?


Затем же самым, зачем строчку

HTTP:=TIdHTTP.Create(MainForm);

ты ОБЯЗАН был синхронизировать.

А ты не сподобился.
Тем самым продемонстрировал непонимание необходимости и необязательности синхронизации.

И таких "чудес" у тебя, видимо, еще немало, судя по многоточию и всяким там "считаем что есть", "считаем что нет"


 
Nil   (2009-08-29 00:38) [4]


> С чего бы вдруг считаем ?

с того что вероятность такого исхода практически равна нулю! это всё равно что  ставить обработку исключения например на выключение света на котором работает программа! это невозможно и моего изначального вопроса никак не касается!

> HTTP:=TIdHTTP.Create(MainForm);

за тем же самым не ответ, поясни если много знаешь! если бы я всё это знал на отлично, я бы не создавал этот топик. но я знаю точно что чтение значения InfoForm.ModalResult не вызывает в VCL никаких событий и определённо точно могу сказать что синхронизировать его не нужно. точно так же как и создание TIdHTTP не инициирует никаких событий связанных с VCL. если я в чём то ошибаюсь, разубеди! только обоснованно!

> Тем самым продемонстрировал непонимание необходимости и
> необязательности синхронизации.

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

и вообще всё это не по теме моего вопроса, то о чём мы сейчас флеймим никак не касается проблем работы инди через прокси


 
CrytoGen   (2009-08-29 08:31) [5]

Молодец, ты всё правильно сделал. Значит всё уже должно работать.


 
Сергей М. ©   (2009-08-29 10:03) [6]

Передача существующего компонента-фладельца Owner параметром в конструктор создаваемого компонента ведет к неявному вызову метода Owner.InsertComponent, который НЕпотокобезопасен.


> это всё равно что  ставить обработку исключения например
> на выключение света на котором работает программа


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


> вылетает Invalid pointer operation. Судя по всему летит оно
> откуда то из недр инди


Судя по ЧЕМУ конкретно ?


 
Nilman ©   (2009-08-31 13:16) [7]


> Передача существующего компонента-фладельца Owner параметром
> в конструктор создаваемого компонента ведет к неявному вызову
> метода Owner.InsertComponent, который НЕпотокобезопасен.
>
>

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

> К чему эти глупости ?
> И вообзще зачем нужна циклическая проверка доступности сервиса
> ?
> Придет время, когда сервис реально понадобится, ты обратишься
> к нему, получишь исключение и сообщишь юзеру о таких-то
> проблемах с сервисом.
> А не получишь - работай дальше с сервисом спокойно.
> Да и нет никакой гарантии, что сервис окажется доступным
> и работоспособным на всем протяжении работы в сеансе подключения
> к нему.
>

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

> Судя по ЧЕМУ конкретно ?

судя по этому коду:

unit Unit1;

interface

uses
 Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
 Dialogs, StdCtrls;

type
 TForm1 = class(TForm)
   Button1: TButton;
   procedure Button1Click(Sender: TObject);
 private
   { Private declarations }
 public
   { Public declarations }
 end;

var
 Form1: TForm1;

implementation

uses IdHTTP, IdExceptionCore, IdHTTPHeaderInfo;

{$R *.dfm}

function NetAvail:boolean;
var
 HTTP: TIdHTTP;
 FServAnsw: WideString;
 IdProxyConnectionInfo: TIdProxyConnectionInfo;
begin
 Result:=False;
 HTTP:=TIdHTTP.Create(Form1);
 IdProxyConnectionInfo:=TIdProxyConnectionInfo.Create;
 try
   HTTP.ReadTimeout:=30000;

     IdProxyConnectionInfo.ProxyServer:="localhost";
     IdProxyConnectionInfo.ProxyPort:=8080;
     IdProxyConnectionInfo.ProxyUsername:="";
     IdProxyConnectionInfo.ProxyPassword:="";
     HTTP.ProxyParams:=IdProxyConnectionInfo;

//      218.248.28.173:3128

   try
     FServAnsw:=Http.Get("http://"+MHost+"/isavail.txt");
   except
     on e: Exception do
       begin
         ShowMessage(e.Message);
       end;
   end;
 finally
   HTTP.Free;
   IdProxyConnectionInfo.Free;
 end;

 if Pos(UnicodeString("ok"),UnicodeString(FServAnsw))>0 then Result:=True;
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
 if NetAvail then ShowMessage("1") else ShowMessage("2");
end;

end.


 
Nilman ©   (2009-08-31 13:23) [8]

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


 
Сергей М. ©   (2009-08-31 13:47) [9]


> в каких то случаях это будет не безопасно


Не в "каких-то", а во всех случаях, когда возможны вызовы метода InsertComponent одновременно более чем из одного потока.


> главная форма перестанет быть только в том случае когда
> все его потомки будут уничтожены


Какие такие "потомки" ?
Я веду речь о форме как компоненте-владельце компонентов.
Компоненты, которыми владеет форма, размещаются в списке Components. Список этот НЕ допускает несинхронизированных обращений к нему. Занесение в список - это InsertComponent, удаление из списка - RemoveComponent.


> какие именно события может вызвать InsertComponent которые
> могут расстроить поток?


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

Например, ты в своем доп потоке создаешь некий компонент

MyComp := TMyComp.Create(форма-владелец); //здесь происходит неявный вызов метода форма-владелец.InsertComponent, добавляющий твой компонент в список компонентов, которыми владеет форма-владелец.
..
MyComp.Free; //а здесь, соотв-но, происходит неявный вызов метода форма-владелец.RemoveComponent, который удалит твой компонент из списка компонентов, которыми владеет форма-владелец.

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

Такая ситуация может привести к непредсказуемым последствиям, вплоть до краха процесса.


> судя по этому коду


Я спросил какая конкретно строчка этого кода вызывает исключение..


 
Nilman ©   (2009-08-31 14:33) [10]


>
> Любые события, влекущие изменение состояния списка Components
> компонента-владельца и потенциально могущие произойти одновременно
> более чем в одном потоке процесса VCL-приложения.
>
> Например, ты в своем доп потоке создаешь некий компонент
>
> MyComp := TMyComp.Create(форма-владелец); //здесь происходит
> неявный вызов метода форма-владелец.InsertComponent, добавляющий
> твой компонент в список компонентов, которыми владеет форма-
> владелец.
> ..
> MyComp.Free; //а здесь, соотв-но, происходит неявный вызов
> метода форма-владелец.RemoveComponent, который удалит твой
> компонент из списка компонентов, которыми владеет форма-
> владелец.
>
> При этом нет никакой гарантии, что те же самые действия
> в те же моменты времени не пытается осуществить какой-либо
> другой поток процесса, например, основной.
>
> Такая ситуация может привести к непредсказуемым последствиям,
>  вплоть до краха процесса.

понял, спасибо за разъяснения! не подумал что RemoveComponent могут вызвать одновременно два компонента..


> Я спросил какая конкретно строчка этого кода вызывает исключение.
> .

ок, тогда попробую максимально подробно. вот здесь вываливается ошибка
FServAnsw:=Http.Get("http://"+MHost+"/isavail.txt");
трасировка довела меня до попытки соединения, CheckAndConnect так по моему называется функция в инди, где возникает исключение, on e: Exception do begin ShowMessage(e.Message); end; выдаёт ошибку сокета, connection refused, а после эксепшена вылетает Invalid pointer operation. Причём это не исключение, а просто ошибка. на сообщение об ошибке только эта фраза и всё. голословность этого сообщение и натолкнуло на мысль что это какая то не обрабатываемая ошибка инди..


 
Сергей М. ©   (2009-08-31 14:52) [11]


> это какая то не обрабатываемая ошибка инди


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


> после эксепшена вылетает Invalid pointer operation


Что значит "после" ?

try
 .. Get ..
except
 on E:Exception do ...
// <-- "после" - это здесь что ли ?
end;


И я что-то не пойму - то ты демонстрируешь код для исполнения в доп.потоке, то теперь для исполнения в основном ..

Т.е. Invalid pointer operation возникает вне зависимости от того, в каком потоке тобой вызывается ф-ция NewAvail() ?

И какая версия Инди используется ?


 
Nilman ©   (2009-08-31 22:17) [12]


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

вполне вероятно что какой то деструктор исключения инди с ошибкой отваливается..

> Что значит "после" ?
>


  try
    FServAnsw:=Http.Get("http://ixitools.com/isavail.txt");
  except
    on e: Exception do
      begin
        ShowMessage(e.Message);
        a:=1;
      end;
  end;

на строчку a:=1 ставлю брэкпоинт, трасировка доходит до ShowMessage, который успешно показывает сообщение об исключении и дальше вываливается Invalid pointer operation.. при этом трасировка до a:=1 не доходит

> И я что-то не пойму - то ты демонстрируешь код для исполнения
> в доп.потоке, то теперь для исполнения в основном ..
>

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

> И какая версия Инди используется ?

10


 
Сергей М. ©   (2009-09-01 10:13) [13]

Т.е. ты утверждаешь, что этот код

try
   FServAnsw:=Http.Get("http://ixitools.com/isavail.txt");
 except
   on e: Exception do
     begin
       ShowMessage(e.Message);
       a:=1;
     end;
 end;


исполняется гарантированно в основном потоке, и при этом ты наблюдаешь ту же самую картину с ошибкой Invalid pointer operation, возникающей при выполнении ShowMessage ?

Ну а не приходило в голову

try
   FServAnsw:=Http.Get("http://ixitools.com/isavail.txt");
 except
 end;

?


 
Nilman ©   (2009-09-03 13:11) [14]

всё таки оказалась кривота не в инди а в моём коде.. странно что про класс TIdProxyConnectionInfo в хелпе видимо забыли или просто порешили что в хелпе ему не место..

проблема была в создании TIdProxyConnectionInfo
так можно:
 HTTP.ProxyParams:=TIdProxyConnectionInfo.Create;
 HTTP.ProxyParams.ProxyServer:=MainForm.AppSettings.ProxyHost;
 ...
так нельзя:
 IdProxyConnectionInfo:=TIdProxyConnectionInfo.Create;
 IdProxyConnectionInfo.ProxyServer:=MainForm.AppSettings.ProxyHost;
 ...
 HTTP.ProxyParams:=IdProxyConnectionInfo;

благодарю за содействие в решении проблемы!

пс
нужно ли руками освобождать idHTTP.ProxyParams? или idHTTP сам сделает это, если ProxyParams не nil?


 
CrytoGen   (2009-09-03 13:42) [15]

это легко проверить :) убей idHTTP и попробуй получить воспользоваться ProxyParams.


 
Сергей М. ©   (2009-09-03 13:52) [16]

Создавать собственный экз-р TIdProxyConnectionInfo вовсе не обязательно.

Его создает сам компонент  TIdHTTP при своей самоинициализации (см. TIdCustomHTTP.InitComponent) и сам же уничтожает его при своем разрушении (см. TIdCustomHTTP.Destroy)

Но если ты все же создал его, то строка
HTTP.ProxyParams:=IdProxyConnectionInfo;
недопустима, ибо она приведет к утечке памяти: компонент TIdHTTP заместит в поле FProxyParameters ссылку на созданный им самим экз-р TIdProxyConnectionInfo ссылкой на твой экз-р БЕЗО всяких проверок (думаю, что это серьезная недоработка разработчиков Инди)

Поступать в таком случае следует так:

IdProxyConnectionInfo:=TIdProxyConnectionInfo.Create;
try
...
  HTTP.ProxyParams.Assign(IdProxyConnectionInfo);
...
finally
  IdProxyConnectionInfo.Free;
end;


 
Nilman ©   (2009-09-03 15:18) [17]

я уже подзапутался.. изначально пробовал так HTTP.ProxyParams.Host:=".." но получал от компилятора ругань, точно какую не помню, но смысл такой что напрямую не могу обращаться к Host. нашёл какой то кусок кода в интернете который говорил что нужно делать так
IdProxyConnectionInfo:=TIdProxyConnectionInfo.Create;
try
...
 HTTP.ProxyParams:=IdProxyConnectionInfo;
...
finally
 IdProxyConnectionInfo.Free;
end;
как я уже говорил тут, что если прокси рабочий то всё проходило нормально, а если же появлялся любой exception сразу получал Invalid pointer operation после exception..
сейчас всё вернулось на свои места, как изначально и предполагалось что должно работать:

 HTTP:=TIdHTTP.Create(MainForm);
 try
   HTTP.ReadTimeout:=30000;

   if MainForm.AppSettings.UseProxy then
   begin
     HTTP.ProxyParams.ProxyServer:=MainForm.AppSettings.ProxyHost;
     HTTP.ProxyParams.ProxyPort:=StrToInt(MainForm.AppSettings.ProxyPort);
     HTTP.ProxyParams.ProxyUsername:=MainForm.AppSettings.ProxyLogin;
     HTTP.ProxyParams.ProxyPassword:=MainForm.AppSettings.ProxyPassw;
//      218.248.28.173:3128
   end;
   try
     FServAnsw:=Http.Get("http://"+MHost+"/isavail.txt");
   except
//      on e: Exception do
//        begin
//          ShowMessage(e.Message);
//        end;
   end;
 finally
   HTTP.Free;
 end;

почему решил попробовать именно так
HTTP.ProxyParams:=TIdProxyConnectionInfo.Create;
потому что раньше встречал где то в стронних компонентах такой подход, что компонент содержит только указатель на объект при этом все действия по инициализации и разрушению оставались на плечах программера.. а вот сразу заглянуть на внутренности TIdCustomHTTP как то и не подумал.

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


 
Сергей М. ©   (2009-09-03 17:00) [18]


> при закрытии программы вся память выделенная программе освобождается,
>  включая этот мой экземпляр TIdProxyConnectionInfo про который
> никто не знает?


Да.


> чем и кому этот подвисший кусок может критически навредить?


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

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


 
Nil   (2009-09-04 23:14) [19]

благодарю!



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

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

Наверх





Память: 0.55 MB
Время: 0.005 c
15-1321002130
Mserrrer
2011-11-11 13:02
2012.02.26
Вопрос по карта (google maps)


2-1320229207
Fr
2011-11-02 13:20
2012.02.26
сокеты и браузер


15-1320674537
mvconf
2011-11-07 17:02
2012.02.26
Разработка системы видеоконференцсвязи


15-1320599461
KilkennyCat
2011-11-06 20:11
2012.02.26
Как пользоваться дебаггером


15-1320945919
РРРС
2011-11-10 21:25
2012.02.26
Точки фриланса





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
Английский Французский Немецкий Итальянский Португальский Русский Испанский