indy TIdHTTP i problem z timerem

0

Witam. Mam problem z poniższym kodem.

  try
    s := Form1.wb.Get('http://www.strona.pl');
    memo1.text := s;
  except
    form1.ListBox1.Items.Insert(0, 'Błąd: #1');
  end;

Jest on zawarty w timerze ustawionym na 1000ms. Zmienna "s" przyjmuje zawartość żądanej strony i jest wyświetlana poprawnie w memo1. Problem w tym, że po około 2-3 minutach pojawia się tylko "Błąd: #1". Uruchamiając program z poziomu delphi pokazuje się debuger CPU i komunikat delphi "Out of memory while expanding memory stream". Próbowałem już po except stosować wb.free i wb.create ale też nie pomogło.

Być może istotna sprawa bo jest to w osobnym wątku. Wygląda to tak:

type
  TSprawdzanie = class(TThread)
  private
    {}
  protected
    procedure Execute; override;
  public
    pierwszy: boolean;
  end;

procedure TSprawdzanie.Execute;
//tutaj ta procedura

W czym może tkwić problem i jak go rozwiązać? Z góry dziękuję za pomoc.

0

Co to jest wb IdHTTP? s to string?
Jaka wersja Indy? Jakie Delphi? Teoretycznie powinno działać bez problemu.

try
  memo1.text:= wb.Get('http://www.strona.pl');
except
  on E: Exception do
    ListBox1.Items.Insert(0, E.Message);
end;

EDIT// No to jak dodałeś że w wątku to czy zwalniasz wątek? Najlepiej daj FreeOnTerminate na True. Jakim cudem w wątku wpisujesz tekst do memo bez synchronize? Daj ten cały kod bo to chyba wszystko do poprawy.

0

Problem wydaje się rozwiązany poprzez wyrzucenie timera i zastosowanie rekurencji (tak mi się wydaje, że to rekurencja)

type
  TForm1 = class(TForm)
    wb: TIdHTTP;
    Timer1: TTimer;
    Lista: TListView;
    onoff: TImageList;
    ListBox1: TListBox;
    procedure Timer1Timer(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
    procedure Wczytaj_Liste;
  end;

type
  TSprawdzanie = class(TThread)
  private
    {}
  protected
    procedure Execute; override;
  public
    pierwszy: boolean;
  end;

var
  Form1: TForm1;
  zrodlo: string;
  wczytana: boolean;
  sprawdz: TSprawdzanie;

implementation

{$R *.dfm}

procedure TSprawdzanie.Execute;
var
  i, dostepnych: integer;
  s, nick: string;
begin
  s := '';

  try
    s := Form1.wb.Get('http://strona.pl');
  except
    form1.ListBox1.Items.Insert(0, 'Błąd: #1');
  end;

  Form1.caption := 'Dostępnych: ' + inttostr(dostepnych);


  sleep(1000);            //Wprowadzenie tego zamiast timera rozwiązało problem
  execute;                 //bynajmniej tak to na razie wygląda. po raz pierwszy execute; wywołane jest w OnCreate formy
end;

end.
0

Powinna to być pętla

while not Terminated do
begin
   //tu cos robisz
   Sleep(1000);
end;

no i w wątku nie wolno się bezpośrednio odwoływać do VCL stosuj Synchronize i zdarzenia

0

Faktycznie ta pętla wydaje się dużo bardziej sensowna za co bardzo Ci dziękuję. Ale jeżeli nie ma możliwości aby wątek był uruchomiony więcej niż jeden raz to czy jest sens używać synchronizacji? Rozdział 8 Tutaj jest napisane, że używa się tego wtedy gdy wątek jest uruchomiony więcej niż raz i modyfikuje zawartość VCL.
I nie rozumiem za bardzo co masz na myśli abym stosował zdarzenia (prawdopodobnie chodzi tu o moje niedouczenie w delphi).

0

Luknij na przykład jak mniej więcej coś takiego powinno wyglądać a jak czegoś nie zrozumiesz to pytaj

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, IdBaseComponent, IdComponent, IdTCPConnection, IdTCPClient,
  IdHTTP, StdCtrls;

type
  TOnAvailUserCountChange = procedure (Sender: TObject; ACount: Integer) of Object;

  TCheckThread = class(TThread)
  private
    fIdHTTP: TIdHTTP;

    fAvailUserCount: Integer;
    fOnAvailUserCountChange: TOnAvailUserCountChange;

    procedure DoOnAvailUserCountChange;
  protected
    procedure Execute; override;
  public
    property OnAvailUserCountChange: TOnAvailUserCountChange read fOnAvailUserCountChange
      write fOnAvailUserCountChange;
    property AvailUserCount: Integer read fAvailUserCount;


    constructor Create;
    destructor Destroy; override;
  end;

  TForm1 = class(TForm)
    IdHTTP1: TIdHTTP;
    ListBox1: TListBox;
    btnStart: TButton;
    btnStop: TButton;
    procedure FormCreate(Sender: TObject);
    procedure btnStartClick(Sender: TObject);
    procedure btnStopClick(Sender: TObject);
    procedure FormCloseQuery(Sender: TObject; var CanClose: Boolean);
  private
    { Private declarations }
    fCheckThread: TCheckThread;
    procedure AvailUserCountChange(Sender: TObject; ACount: Integer);
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TCheckThread.DoOnAvailUserCountChange;
begin
  fOnAvailUserCountChange(Self, fAvailUserCount);
end;

procedure TCheckThread.Execute;
const
  GOOGLE_URL = 'http://google.pl';
var
  html: String;
  fActualUserCount: Integer;
begin
  while not Terminated do
  begin
    try
      //tu cos co ma watek robic ja dla jaj pobiore strone google
      html:= fIdHTTP.Get(GOOGLE_URL);
      //a tu przyklad zdarzenia widzialem ze tam cos grzebierz w kodzie
      //i pobierasz ilosc sostepnych ludzi ja nie wnikam w to tylko wezme
      //losowoa wartosc
      fActualUserCount:= Random(11);;
      if fActualUserCount <> fAvailUserCount then
      begin
        fAvailUserCount:= fActualUserCount;
        if Assigned(fOnAvailUserCountChange) then
          Synchronize(DoOnAvailUserCountChange);
      end;
      Sleep(1000);
    except
    //tu reakcja na bledy (ja je zwyczajnie olewam)
    end;
  end;
end;

constructor TCheckThread.Create;
const
  UA = 'Mozilla/5.0 (Windows NT 5.1; rv:15.0) Gecko/20100101 Firefox/15.0.1';
begin
  inherited Create(True);
  Self.FreeOnTerminate:= True;
  fOnAvailUserCountChange:= nil;
  fAvailUserCount:= 0;
  fIdHTTP:= TIdHTTP.Create;
  fIdHTTP.Request.UserAgent:= UA;
  fIdHTTP.HandleRedirects:= True;
end;

destructor TCheckThread.Destroy;
begin
  if Assigned(fIdHTTP) then
    fIdHTTP.Free;
end;

procedure TForm1.AvailUserCountChange(Sender: TObject; ACount: Integer);
begin
  ListBox1.Items.Add(IntToStr(ACount));
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  Randomize;
  fCheckThread:= nil;
end;

procedure TForm1.btnStartClick(Sender: TObject);
begin
  if not Assigned(fCheckThread) then
    fCheckThread:= TCheckThread.Create;
  fCheckThread.OnAvailUserCountChange:= AvailUserCountChange;
  fCheckThread.Resume;
end;

procedure TForm1.btnStopClick(Sender: TObject);
begin
  if Assigned(fCheckThread) then
    fCheckThread.Terminate;
  fCheckThread:= nil;
end;

procedure TForm1.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
begin
  btnStop.Click;
end;

end.
0

kAzek jesteś wielki. Dziękuję Ci bardzo

1 użytkowników online, w tym zalogowanych: 0, gości: 1