Recent

Author Topic: [SOLVED ]Catching TFPHTTPClient timeout and avoid freeze  (Read 5895 times)

torbente

  • Sr. Member
  • ****
  • Posts: 325
    • Noso Main Page
[SOLVED ]Catching TFPHTTPClient timeout and avoid freeze
« on: May 30, 2018, 05:00:30 pm »
I use this simple function to read data from webpages

Code: Pascal  [Select][+][-]
  1. function Read_URL_GET(url:string):string;
  2. begin
  3. with TFPHTTPClient.Create(nil) do
  4.   try
  5.     Read_URL_GET:= Get(url);
  6.   except
  7.     on E:Exception do
  8.        begin
  9.        Read_URL_GET:= 'ERROR';
  10.        end;
  11.   end;
  12. end;

It returns 'ERROR' when something go wrong, but if the page do not responds, it freeze the app meanwhile. Are there any simple way to avoid this situations?
« Last Edit: June 01, 2018, 01:11:42 pm by torbente »
Noso Cryptocurrency Main Developer
https://github.com/DevTeamNoso/NosoWallet

Leledumbo

  • Hero Member
  • *****
  • Posts: 8746
  • Programming + Glam Metal + Tae Kwon Do = Me
Re: Catching TFPHTTPClient timeout
« Reply #1 on: May 31, 2018, 05:47:32 am »
It returns 'ERROR' when something go wrong, but if the page do not responds, it freeze the app meanwhile. Are there any simple way to avoid this situations?
Wrap in a thread.

balazsszekely

  • Guest
Re: Catching TFPHTTPClient timeout
« Reply #2 on: May 31, 2018, 06:33:21 am »
I agree with Leledumbo, without a worker thread this issue is unsolvable. More useful info: http://forum.lazarus.freepascal.org/index.php/topic,38472.0.html

torbente

  • Sr. Member
  • ****
  • Posts: 325
    • Noso Main Page
Re: Catching TFPHTTPClient timeout
« Reply #3 on: May 31, 2018, 03:57:22 pm »
ok, y make it work with threads (timer1.interval := 3000 here)

Code: Pascal  [Select][+][-]
  1. var
  2.   numero : integer;
  3.  
  4. procedure readfromweb();
  5. begin
  6. form1.memo1.lines.add(read_url_get('https://myweb.com/sleep.php')); // this pages delays 10 seconds to answer
  7. form1.timer1.Enabled:=false;
  8. end;
  9.  
  10. procedure TForm1.Button1Click(Sender: TObject);
  11. begin
  12. timer1.Enabled:=true;
  13. numero := BeginThread(TThreadFunc(@readfromweb));
  14. end;
  15.  
  16. procedure TForm1.Timer1Timer(Sender: TObject);
  17. begin
  18. memo1.lines.add('Server is down or busy. Try again later.');
  19. KillThread(numero);
  20. timer1.Enabled:=false;
  21. end;

Can this be sintetized in one function?? Somehting like...

Code: Pascal  [Select][+][-]
  1. function IsServerOnline():boolean;
  2. begin
  3. // all the previous code here...
  4.  IsServerOnline := true; // Or false
  5. end;
« Last Edit: May 31, 2018, 03:58:57 pm by torbente »
Noso Cryptocurrency Main Developer
https://github.com/DevTeamNoso/NosoWallet

af0815

  • Hero Member
  • *****
  • Posts: 1289
Re: Catching TFPHTTPClient timeout
« Reply #4 on: May 31, 2018, 04:03:52 pm »
I think it is not a good idea to use visual components like memo inside of threads.

See http://wiki.freepascal.org/Multithreaded_Application_Tutorial and https://forum.lazarus.freepascal.org/index.php/topic,38851.msg265181.html#msg265181 ... and alot of other posts ...
regards
Andreas

torbente

  • Sr. Member
  • ****
  • Posts: 325
    • Noso Main Page
Re: Catching TFPHTTPClient timeout
« Reply #5 on: May 31, 2018, 04:11:20 pm »
The memo is only for testing. I only need know if the server is responding in less than 3 second.
I had read a lot of posts, and im still searching for new ones.

I think it is not a good idea to use visual components like memo inside of threads.

See http://wiki.freepascal.org/Multithreaded_Application_Tutorial and https://forum.lazarus.freepascal.org/index.php/topic,38851.msg265181.html#msg265181 ... and alot of other posts ...
Noso Cryptocurrency Main Developer
https://github.com/DevTeamNoso/NosoWallet

balazsszekely

  • Guest
Re: Catching TFPHTTPClient timeout
« Reply #6 on: May 31, 2018, 04:31:56 pm »
@torbente
Quote
Can this be sintetized in one function?? Somehting like...
Not in a function, no. But in a class yes.
I already gave you an example how to do a http requests(download file, parse webpage to a string, post files, etc...) in a worker thread. Take a look at the attachment in this post(uhttprequest.pas): http://forum.lazarus.freepascal.org/index.php/topic,41310.msg286833.html#msg286833
You have to modify it a little bit, rewrite the Execute method, set fphttpclient.timeout and you're good to go. Also take into account this post: http://forum.lazarus.freepascal.org/index.php/topic,38472.msg261333.html#msg261333
Basically everything is implemented, but I'm not gonna spend another half our writing a test project :)
« Last Edit: May 31, 2018, 04:33:42 pm by GetMem »

torbente

  • Sr. Member
  • ****
  • Posts: 325
    • Noso Main Page
Re: Catching TFPHTTPClient timeout
« Reply #7 on: June 01, 2018, 09:59:04 am »
@getmem

First, i really apreciated your time and help.  :)

I read and run your code, and i do not understand many things (i had never worked with classes, for example). But for what i understood from your test project, it is the same thing i posted in this topic, but with another aproach. Anyway, i will use it to study and try to learn using reverse engineering  :D

What i can do with my (very) limited lazarus/fpc knowledge looks easy to do, but not in an "elegant" (or easy) way. I was thinking in a possible solution, but due to the very hard job it minds for my entire project, this is the basic idea(i will create a backup of my project first anyway)(off topic: it is time to add a simple "Rename Project" option to the lazarus GUI)

Code: Pascal  [Select][+][-]
  1. var // Global
  2. URLtoRead : string;
  3. StringFromURL : string;
  4. ThreadNumber:Integer;
  5.  
  6. procedure Read_URL_GET();
  7. begin
  8. with TFPHTTPClient.Create(nil) do
  9.   try
  10.     StringFromURL := Get(URLtoRead);
  11.   except
  12.     on E:Exception do
  13.        begin
  14.        StringFromURL := 'ERROR';
  15.        end;
  16.   end;
  17. end;
  18.  
  19. procedure GetDataFromServer(URL:String;TimeOUTQuery:integer);
  20. begin
  21. URLtoRead  := URL;
  22. StringFromURL  := 'DOWN': // set by default
  23. ThreadNumber:= BeginThread(TThreadFunc(@Read_URL_GET));
  24. WaitForThreadTerminate(ThreadNumber,TimeOUTQuery);
  25. end;


EDITED: This is working perfectly (until now)!! I even dont need a timer.

Code: Pascal  [Select][+][-]
  1. GetDataFromServer('https://myweb.com/',1500); // this page returns 'ok'
  2. if StringFromURL  = 'DOWN' then // what to do if server is down
  3. else if StringFromURL = 'ERROR' then // if the server gives a bad answer
  4. else // and here what to do if everything go fine
  5.  ;

I dont know if this code could be improved, but do the job.
« Last Edit: June 01, 2018, 10:45:21 am by torbente »
Noso Cryptocurrency Main Developer
https://github.com/DevTeamNoso/NosoWallet

d.ioannidis

  • Full Member
  • ***
  • Posts: 221
    • Nephelae
Re: [SOLVED ]Catching TFPHTTPClient timeout and avoid freeze
« Reply #8 on: June 09, 2018, 09:30:57 pm »
Hi,

  if you use fpc trunk, today the issue 33745 TInetSocket connect timeout is resolved, so you can use the following code  :

Code: Pascal  [Select][+][-]
  1.     function Read_URL_GET(url:string):string;
  2.     begin
  3.     with TFPHTTPClient.Create(nil) do
  4.       try
  5.         ConnectTimeout := 2000;    <-- Add this line.
  6.         Read_URL_GET:= Get(url);
  7.       except
  8.         on E:Exception do
  9.            begin
  10.            Read_URL_GET:= 'ERROR';
  11.            end;
  12.       end;
  13.     end;

  if the connection can't be established it raises a seConnectTimeOut exception.

 regards,

 

TinyPortal © 2005-2018