Navigacija
Lista poslednjih: 16, 32, 64, 128 poruka.

TCPserver Indy9/Delphi7 problem

[es] :: Pascal / Delphi / Kylix :: TCPserver Indy9/Delphi7 problem

[ Pregleda: 2358 | Odgovora: 7 ] > FB > Twit

Postavi temu Odgovori

Autor

Pretraga teme: Traži
Markiranje Štampanje RSS

salaczr

Član broj: 160654
Poruke: 103
94.189.232.*



+5 Profil

icon TCPserver Indy9/Delphi7 problem15.12.2008. u 12:16 - pre 187 meseci
Potreban mi je nacin kako da utvrdim koliko dugo je neki Thread aktivan, pa u zavisnosti od proteklog vremena da ga gasim ili da ga ostavim u "zivotu".
Trenutno program radi kao serverska aplikacija na koju se kace klijenti (njih oko 1000), preko GPRS-a. Komunikacija izmedju klijenta i servera je sledeca: klijent pristupi serveru i otvara socket, u okviru jednog socket-a on kreira nekoliko thread-ova (u zavisnosti sta klijent zeli od servera) i po obavljenom poslu klijent gasi konekciju (zatvara socket). Problem je u sledecem, ukoliko cela komunikacija protekne bez problema svaki kreirani thread se i gasi, medjutim ukoliko komunikacija (uglavnom zbog nepouzdanosti GPRS-a) ne ode do kraja, thread ostaje da "zivi" i socket ostaje otvoren. Pokusao sam da preko ThreadList-e nadjem spisak svih aktivnih thread-ova, ali nisam uspeo da proverim koliko je vremena proteklo od kada je thread kreiran. Jos jedna stvar aplikacija koju radim izvrsava se na Linux-u i nemam mogucnost da koristim TTimer komponentu, jer ona (izgleda) poziva neke X-server biblioteke, a na nasem serveru nije instaliran nikakav graficki interfejs. Ukoliko neko ima resenje ili se sreo sa istim problemom neka pise.
poZ
 
Odgovor na temu

Rapaic Rajko
Bgd

Član broj: 4105
Poruke: 810
93.86.154.*



+62 Profil

icon Re: TCPserver Indy9/Delphi7 problem15.12.2008. u 13:36 - pre 187 meseci
Da li ti pises, to jest imas pristup kodu kompletnog projekta?

Evo zasto te pitam. Self-destroy je najbolji nacin ubijanja thread-a; a kako sam te razumeo, ti hoces da isti ukokas spoljnom intervencijom. Ne znam kako to ide na Linux-u, ali u Windows-u se koristi API funkcija TerminateThread(), uz koju ide POVECI warning zasto je NE treba koristiti. Pocev od neoslobodjenih resursa, pa sve do mogucnosti da abandon-ujes recimo neki dll iz kojeg se pomenuti thread lansira, itd.itd.

Ako imas pristup kodu, pravi nacin bi bio da izmenis kod, odnosno ugradis metode u socket koje ce da rade sa thread-ovima. To zato sto je on ocigledno owner thread-ovima, i ne moze da se samo-zatvori dokle god su njegovi child thread-ovi zivi. Dalje, uradis izmene i u kodu thread-ova, tako da periodicno proveravaju neki svoj flag (koji je dostupan i socket objektu), i cim se flag promeni (od strane socket-a), sami se potabaju.

E sad, ako su thread-ovi pisani da rade u sinhronom modu (recimo za komunikaciju), stvar je malo slozenija. Thread ne moze sam sebe da ubije, ako je recimo u pozivu ReadFile() u sinhronom modu. Ali se moze nesto drugo: spolja ubijemo/discard-ujemo HANDLE koji je (prvi) argument te funkcije. Funkcija smesta izlazi iz poziva, vraca gresku, thread-objekat identifikuje gresku i okoncava svoj (jadan) zivot ;) .

Ako je nesto drugo u pitanju, ili ako nisu ispunjene gornji preduslovi (uvid u kod), daj onda malo detaljnije...

EDIT: i da, pomenuo si TTimer. Pa ne treba ti, sigurno na Linux-u postoji ekvivalent funkcije GetTickCount(), kad se thread kreira, samo zapise taj svecani trenutak u svoj neki field, na koji imas public property i to je to. Ali opet kazem, bolje je da sam thread vodi racuna o svom zivotnom veku (nego neko spolja).

Pozzz

Rajko
 
Odgovor na temu

savkic
Igor Savkić

Moderator
Član broj: 92186
Poruke: 2739



+92 Profil

icon Re: TCPserver Indy9/Delphi7 problem15.12.2008. u 14:07 - pre 187 meseci
> sledeca: klijent pristupi serveru i otvara socket, u okviru jednog socket-a on kreira nekoliko thread-ova (u zavisnosti sta klijent
> zeli od servera) i po obavljenom poslu klijent gasi konekciju (zatvara socket). Problem je u s

Imaj na umu da i TIdTCPServer za svaku konekciju pravi poseban thread, možda ti dodatni thredovi nisu ni potrebni.

> Problem je u sledecem, ukoliko cela komunikacija protekne bez problema svaki kreirani thread se i gasi, medjutim ukoliko komunikacija (uglavnom zbog
> nepouzdanosti GPRS-a) ne ode do kraja, thread ostaje da "zivi" i socket ostaje otvoren.

Možeš periodično pokušavati da šalješ neki paket klijentu (keep alive), ako je socket pukao server komponenta bi to trebalo da detektuje na taj način.

> Pokusao sam da preko ThreadList-e nadjem spisak svih aktivnih thread-ova,

Bolje je koristiti Contexts (barem se tako zove u Indy10, nemam 9 da proverim) server klase, to je spisak svih konekcija.

> ali nisam uspeo da proverim koliko je vremena proteklo od kada je thread kreiran.

Samo sačuvaj vreme kada je uspostavljena konekcija (OnConnect event), Now će biti dovoljan. Ako nemaš izvedenu klasu od TIdContext koji predstavlja klijentsku konekciju napravi niz recorda:
TConnTime = record
Conn: TObject;
ConnectedTime: TDateTime;
end;

> Jos jedna stvar aplikacija koju radim izvrsava se na Linux-u i nemam mogucnost da koristim TTimer komponentu,

TTimer ti ne bi trebao ni na Windowsu. BTW u čemu radiš FPCu ili Kylixu?
 
Odgovor na temu

salaczr

Član broj: 160654
Poruke: 103
94.189.232.*



+5 Profil

icon Re: TCPserver Indy9/Delphi7 problem15.12.2008. u 14:12 - pre 187 meseci
Prvo, hvala na tako brzom odgovoru, pokusao sam da sto vise priblizim problem (valjda sam se zbog toga i tako raspisao), ali ovako:
evo malo koda
Code:

with AThread.Connection do
     begin
         s := ReadLn;
         IP := Socket.Binding.PeerIP;
         Port := IntToStr(Socket.Binding.PeerPort);

       // nesto se radi u zavisnosti od toga sta je stiglo

         Writeln (Odgovor);
     end;

Slazem se sa tvojom konstatacijom da je najbolje pusti thread-ove da sami "umru", ali problem je , kao sto napisah, u tome da se komunikacija
izmedju klijenta i servera odvija kroz vise thread-ova u okviru jednog socket-a. I sve je uredu kada se ispostuje cela komunikacija (odnosno kada
stigne FIN_FLAG od klijenta), medjutim kada nastane zastoj ili u komunikaciji, socket ostaje otvoren, i jedi nacin je da sam serverski program
preuzme na sebe da ih gasi. Donekle sam resio problem kada sam napisao jednu proceduru kojom gasim prvih 15 clanova ThreadList-e (nije bas
najsrecnije resenje), kada ih bude ukupno 30 (u statusu ESTABLISHED), ali resenje nije dobro jer ne uspevam da ih se oslobodim (neki od njih "zive"
i po vise sati, jer se procedura okida kada ih u ThreadList-i bude vise od 30).
Evo koda:
Code:

procedure CloseSocket;
var
  List : Tlist;
  i : integer;
begin
    try
      List := TCP4889.Threads.LockList;
      if List.Count > 29 then
         begin
            for i := 0 to 14 do
                 try
                   TIdPeerThread(List.Items[i]).Connection.Socket.Close;
                 except
                    on e: exception do System.WriteLn(e.Message);
                 end; 
            for i := 0 to 14 do
                TCP4889.Threads.Remove(List.Items[0]);         
    finally
      TCP4889.Threads.UnlockList;
    end;
end; 

Iako ih ova procedura zatvara i brise iz liste oni ipak ostaju da zive na sistemu. Pretpostavljam da bi resenje bilo slucaj kada bih mogao
da izmerim duzinu "zivota" socketa, i ukoliko je on, na primer, duzi od 3 minuta da ga automatski zatvaram sa strane servera.
poZ

ps sad sam video poruku od Savkica, radim u Delphi7 ali koristim CrossKylix compiler za generisanje Linux programa.


EDIT (savkic): dodao sam code tagove tako da poruka bude lakša za praćenje.


[Ovu poruku je menjao savkic dana 15.12.2008. u 15:51 GMT+1]

[Ovu poruku je menjao savkic dana 15.12.2008. u 15:51 GMT+1]
 
Odgovor na temu

savkic
Igor Savkić

Moderator
Član broj: 92186
Poruke: 2739



+92 Profil

icon Re: TCPserver Indy9/Delphi7 problem15.12.2008. u 14:47 - pre 187 meseci
Po meni je najbolje dodatne threadove vezati za konekciju tako da kada se konekcija zavrsi zavrse se i threadovi. Potrebno je da handlujes OnDisconnect (i OnConnect) event TIdTCPServera. Periodično šalji keep alive poruke što će biti dovoljno da IdTCPServera detektuje većinu ugašenih konekcija (socketa) i da pozove cleanup kod (i OnDisconnect). Za ostale ćeš morati da proveravaš vreme uspostavljanja konekcije i da ih gasiš, gašenje se radi sa Client.Connection.Disconnect(True);

Kako ti izgleda OnTCPExecute handler?
 
Odgovor na temu

salaczr

Član broj: 160654
Poruke: 103
94.189.232.*



+5 Profil

icon Re: TCPserver Indy9/Delphi7 problem16.12.2008. u 09:03 - pre 186 meseci
Uffffff, izgleda da ja ne znam da objasnim problem ;(. Ukoliko bih mogao da handlujem OnDisconnect, ne bih imao problem, jer ako dodje do toga nema potreba da bilo sta ja tu radim. Drugi problem je sto komunikaciju ne mogu da iniciram ja (server-side) vec samo opsluzujem gomilu "nepredvidivih" klijenata, mozda bih mogao da probam to sa slanjem keep alive poruka za one Thread-ve koji su aktivni, ali nisam uspeo da nadjem kako se to radi u Indy9. Imao sam ideju da resim to na sledeci nacin:
Code:

type
  PClient   = ^TClient;
  TClient   = record
    PeerIP       : string[15];  
    PeerPort    : integer;
    Connected : TDateTime; 
    ThreadId      : Pointer;   
  end;
....
var
  Clients : TThreadList;


Pa da za svaki kreiran thread upisem njegove podatke u slog i proveravam da li je vreme koje je proslo od kada je kreiran thread (Connected) vise od 5 minuta, pa da gasim taj thread (ThreadId), ali cini mi se suvise opterecujuce za sam program i cini mi se velika sansa za neki "nicim izazvan" memory leak.
Ako neko ima neku drugu ideju, savet ili bilo sta neka napise.
poZ
 
Odgovor na temu

savkic
Igor Savkić

Moderator
Član broj: 92186
Poruke: 2739



+92 Profil

icon Re: TCPserver Indy9/Delphi7 problem16.12.2008. u 13:26 - pre 186 meseci
> Uffffff, izgleda da ja ne znam da objasnim problem ;(. Ukoliko bih mogao da handlujem OnDisconnect, ne bih imao problem, jer ako
> dodje do toga nema potreba da bilo sta ja tu radim.

A zašto ne možeš? Evo upravo gledam help za Indy9 i TIdTCPServer ima OnDisconnect event, takođe vidim da postoji TIdTCPConnection.OnDisconnected jedan od njih se mora pozvati.

> Drugi problem je sto komunikaciju ne mogu da iniciram ja (server-side) vec samo opsluzujem gomilu "nepredvidivih" klijenata,

Konekciju naravno ne možeš jer si ti server ali zato možeš da šalješ podatke klijentu kada ti poželiš nezavisno od toga da li ti je stiglo od njega. To je tzv. keep alive paket, pošalješ bilo šta, možda WriteLn('PING') ili nešto drugo što neće uticati na rad klijenta.

> ali nisam uspeo da nadjem kako se to radi u Indy9. Imao sam ideju da resim to na sledeci nacin:

Code:

var
  List : Tlist;
  i : integer;
begin
   List := TCP4889.Threads.LockList; 
   try
      for i := 0 to List.Count  - 1 do
       begin
          TIdPeerThread(List.Items[i]).Connection.WriteLn('PROBA');  // Saljes nesto 
         TIdPeerThread(List.Items[i]).Connection.Disconnect; // Gasis konekciju
       end;
    finally
      TCP4889.Threads.UnlockList;
    end;
 


Code:

  TClient   = record
    PeerIP       : string[15];  
    PeerPort    : integer;
    Connected : TDateTime; 
    ThreadId      : Pointer;   
  end;


Mislim da je bolje da napraviš naslednika od TIdPeerThread koji ćeš koristiti kao client class i onda u njemu dodaš potrebna polja.

> ali cini mi se suvise opterecujuce za sam program i cini mi se velika sansa za neki "nicim izazvan" memory leak.

Prolazak kroz jednu takvu listu se neće ni osetiti, slobodno to uradi. A do curenja memorije nema razloga da dođe.
 
Odgovor na temu

salaczr

Član broj: 160654
Poruke: 103
94.189.232.*



+5 Profil

icon Re: TCPserver Indy9/Delphi7 problem22.12.2008. u 13:00 - pre 186 meseci
Pozdrav,
prvo da se zahvalim gospodi Rapajicu i Savkicu sto su odvojili svoje vreme da mi pomognu da resim svoj problem. Posle mnogo izgubljenih zivaca
uspeo sam da se pomaknem sa mrtve tacke. Uspeo sam u pokusaju da neaktivne konekcije gasim ali i da "oslobodim" thread-ove koji su bili deo
otvorenih socket-a. Zbog truda doticne gospode i ostalih koji su pratili temu zeleo bih da prezentujem svoje resenje, nazalost jos uvek ne konacno.
Code:

procedure CloseSocket;
var
  List : Tlist;
  i : integer;
begin
    try
      List := TCP4889.Threads.LockList;
      if List.Count > 29 then
         begin
            for i := 0 to 14 do
                 try
                   TIdPeerThread(List.Items[i]).Connection.Socket.Close;
                   TIdPeerThread(List.Items[i]).Terminate;        //  ovo je resilo problem
                 except
                    on e: exception do System.WriteLn(e.Message);
                 end;     
    finally
      TCP4889.Threads.UnlockList;
    end;
end; 

Sada nema gomilanja thread-ova u nedogled, vec kada lista (ThreadList) sadrzi informacije o vise od 30 aktivnih thread-ova (samo nekolicina njih
je stvarno aktivna), gore napisana procedura zatvara socket i thread-ove prvih 15 (hronoloski). Kada budem resio problem do kraja javi cu se da
prezentujem konacno resenje.

poZ
 
Odgovor na temu

[es] :: Pascal / Delphi / Kylix :: TCPserver Indy9/Delphi7 problem

[ Pregleda: 2358 | Odgovora: 7 ] > FB > Twit

Postavi temu Odgovori

Navigacija
Lista poslednjih: 16, 32, 64, 128 poruka.