Newsgroup: it.comp.lang.delphi
Titolo: indy TCPServer

ciao a tutti, quando si utilizzano i socket server, che componente č meglio 
usare per memorizzare i vari messaggi che arrivano??? essendo un thread come 
posso memorizzare tutti i messaggi e poi processarli?
Simone 


Ciao,
dipende un pò da quello che devi fare. Se devi ricevere dei comandi (ad.
es. SIGNON, SIGNOFF, ecc) conviene usare un TidCMDTCPServer, se devi
ricevere messaggi generici puoi usare un TidTCPServer.
La seconda domanda non la comprendo bene, credo che tu intenda dire come
processare i vari messaggi mano a mano che arrivano... giusto?
Nel caso del TidCMDTCPServer, quando arriva un determinato comando il
componente attiva l'evento corrispondente e quindi da li effettui tutte le
operazioni necessarie. Nel caso del TidTCPServer, hai il metodo OnExecute.
Piccola precisazione : gli eventi, in entrambi i server, sono Threaded,
cioè vengono eseguiti parallelamente al corso del programma stesso. E
parallelamente anche in caso di più client connessi. Ma questo credo che
non sia un problema per te.
Ciao
Cristiano
--- posted by geoForum on 
http://www.delphiedintorni.it

 posso memorizzare tutti i messaggi e poi processarli?
Spiega meglio che cosa vuoi fare.
-- 
questo articolo e` stato inviato via web dal servizio gratuito 
http://www.newsland.it/news
 segnala gli abusi ad 
ab...@newsland.it

allora... io già uso TidTCPServer e guardo i messaggi che arrivano 
onExecute... però quando arrivano contemporaneamente piu' messaggi non so 
cosa utilizzare per evitare access violation (es. se uso un memo oppure un 
listbox in contemporanea mi da errore)
Simone

non sia un problema per te.
Io sulla documentazione leggo che per ogni connessione attiva esiste
un thread,
e che questi thread vengono gestiti simultaneamente. Mi sembra che
quindi
non si possa, sulla stessa connessione, leggere comandi in
parallelo...
sbaglio?



Il tuo codice deve essere thread-safe, vale a dire o non usi le stesse
risorse all'interno dei tuoi thread, oppure gestisci l'utilizzo di
tali risorse serializzandolo (TCriticalSection, ...).
Se poi devi interagire con il video direi che devi ricorrere alla
Syncronize, documentati in questa direzione.
Occhio che se serializzi pesantemente finisci per non avere più un
applicazione che lavora in modo "parallelo", non so se mi sono
spiegato..

Simone P. ha scritto:

"Access violation" vuol dire tutto e niente. Il problema è che stai
lavorando in un contesto multithread, quindi devi necessariamente, in
qualche punto, sincronizzare l'accesso a risorse condivise, sia in lettura
(laddove non possa essere atomica) che in scrittura. Evita il più
possibile la Synchronize e le corse critiche, perché sei a continuo
rischio di deadlock. Affidati, invece, ai messaggi di Windows per far
comunicare i thread secondari col thread principale dell'applicazione. 


basterebbe una cosa del genere?
uses
  SyncObjs;
// one lock for each independent resource
var
  myLock : TCriticalSection;
// early during application startup:
myLock := TCriticalSection.Create; 
procedure TMyThread.Execute;
begin
  //... lock it
  myLock.Acquire; 
  // use the shared resource
  // unlock it..
  myLock.Release;
end;

   myLock.Release;
Questa operazione va, tipicamente, in un blocco finally.
Altrimenti vai incontro ai problemi di dead-lock a cui facevo riferimento.



Ciao SerFingolfin, 
no, non sbagli, non mi sono espresso correttamente, ho omesso di indicare
che il thread coinvolge la connessione, ma i comandi inviati (in maniera
sequenziale per ogni connessione) sono comunque paralleli all'esecuzione
del programma stesso (ovviamente... essendo dei thread).
Spero di aver riparato al mio errore ;-))
Ciao.



wrote:


 i comandi in arrivo su una singola connessione?
Questa richiesta non ha molto senso: se esiste un thread per connessione è
proprio perché i dati della singola connessione sono sequenziali e quindi
un thread gestisce il flusso in ingresso e in uscita. "Processare
parallelamente"  significa creare dei percorsi secondari di esecuzione
(thread e/o processi).
Dovresti spiegare dettagliatamente che cosa vuoi fare.


Vorrei solamente sapere se sia possibile o meno
eseguire un comando (con durata arbitraria dell'esecuzione)
e contemporaneamente "leggere" il socket per attendere,
ad esempio un comando di "break" dell'esecuzione precedente.


Ciao, 
Sono d'accordo con quanto ha detto sopra Andrea La Forgia, cioč che i
dati, per singola connessione sono sequenziali.
Certo tutto si puň fare... potresti far partire un altro thread creato da
te quando esegui un comando lungo e rilasciare il thread della connessione
TCPServer... Ma mi sembra una cosa alquando scorretta, anche perchč mi
aspetto che ci sia un client che stia attendendo una risposta, piů o meno
lunga che possa essere... Perň dipende tutto da quello che vuoi fare tu..


Sono anche io d'accordo con te, non è una cosa molto
corretta ed elegante.
Comunque sarebbe il thread client stesso che ha inviato
il comando "a lunga esecuzione" a deciderne lo stop
tramite comando opportuno. Per questo, immagino, da
quanto scrivete, sia necessario impostare una connessione diversa
dalla prima...



Non so se ho capito il senso che vuoi dare alla cosa, però mi verrebbe
da pensare che se una volta ricevuto un comando (che come detto è un
thread) crei un altro thread per la sua esecuzione, sblocchi di fatto
il socket.
Nel senso che a quel punto puoi continuare a scambiare byte sul tuo
socket mentre l'elaborazione del comando procede...
Forse sapendo lo scopo finale si puo ideare qualcosa di meno contorto.
Ciao

SerFingolfin ha scritto:

Non con questo tipo di gestione (sincrona, multithread) e no, a meno di
costruire altri thread, che come già detto in precedenza, complica le cose.



Ciao, 
se hai intenzione di usare thread per eseguire delle operazioni lunghe,
converrebbe, a mio avviso, tenere traccia dei thread lanciati con una
lista TthreadList (che altri non è che una Tlist con una sezione
Critical), così da poterne sempre tenere traccia nel programma, anche
dagli altri thread del TCPServer (sia esso TidCMDTCPServer che
TidTCPServer) onde evitare di lanciare più volte lo stesso comando.... o
per verificare, prima di lanciarlo che non sia già in esecuzione.
Ovviamente, prima di leggere e/o scrivere la TThreadList ricorda di fare
un locklist e quando hai finito di fare un UnlockList, così, con la prima
istruzione la congeli temporaneamente e la seconda lo scongeli permettendo
anche agli altri Thread di poterla leggere.
A questo punto, con un comando potresti lanciare il thread "lungo",
immettere il suo puntatore e i suoi riferimenti nella TThreadList e poi
rilasciare la connessione con il client, così continua il suo lavoro.
Quando il thread "lungo" finisce il suo lavoro potrebbe cancellare il suo
riferimento dalla TThreadList così che se un client richiede di nuovo il
lavoro "lungo", il server non lo trova e lo avvia... viceversa, se il
server, scorrendo la lista dei lavori nella TThreadList trova il lavoro
ancora registrato potrebbe restituire un messaggio di errore. Per essere
"puliti" dovremmo mandare un messaggio di fine esecuzione al client...
Eventualmente se il client volesse fermare l'esecuzione del thread "lungo"
invierebbe un comando al server che controlla se il Thread "lungo" è in
esecuzione e lo ferma, viceversa restituisce l'errore.
Tutto questo te lo dico in via teorica... visto che non ho mai realizzato
una cosa del genere. Fino ad adesso solo comandi "sequenziali" e quindi
che non lanciavano un'altro thread... sta a te provare..



wrote:

Grazie mille. Tenterò l'impresa e posterò gli esiti!

 Grazie mille. Tenterò l'impresa e posterò gli esiti!
Per una soluzione simile (accumulo di thread che processano lo stesso
messaggio) io ho seguito una logica di questo tipo: 
1 - Ho specializzato una classe apposita file->new->other->threadobject
2 - ho aggiunto il costruttore personalizzato con un parametro che contiene
il messaggio 
3 - nel costruttore ho memorizzato il parametro messaggio impostato
FreeOnTerminate := False;
3- nel metodo execute ho messo la logica di processo del messaggio
a questo punto ho scritto un manager (un processo gestore) che contiene una
tlist, dove memorizzo tutti i thread che alloco.
Ad ogni messaggio arrivato, istanzio un nuovo thread, gli passo il
messaggio nel costruttore, gli do' il resume.
Quando decido di rimuovere il manager, allora il manager prende la lista di
thread, e fa la free di tutti quelli che hanno terminato l'elaborazione
(indicata da una property readonly che imposto internamente al thread a
fine esecuzione) fino a che tutti sono stati distrutti.
PRO di questa soluzione: hai un modello da applicare ogni qualvolta devi
spostare il *peso* elaborativo da un processo ad un'altro. (nel mio caso si
tratta di operazioni pesanti sul database di diversi minuti, che ho
parallelizzato e rilocato ad un processo padre (il manager è istanziato in
questo processo) 
CONTRO di questa soluzione: non libera le risorse allocate immediatamente,
ma lo devi fare tu esplicitamente dal manager. Non tiene conto della
sequenzialità dei messagi: ogni thread ha vita propria e non interferisce
su dati di altri thread (no syncronize).
Scegli tu calibrando bene il peso dei processi che devi istanziare quale
sia il modello da adottare. E pubblicalo, cosi' condividiamo conoscenza.
Mi sono dimenticati di dirti che non uso gli indy, in questo contesto
lancio stored procedure su un grosso database: forse non fa al caso tuo, ma
tant'è: volevo darti un'altra idea su cui pensare... ;)
Ciao 
-- 
Morde

comunicare i thread secondari col thread principale dell'applicazione. 
Se non ti dispiace vorrei approfondire il discorso messaggi, mentre mi
è chiaro il loro utilizzo in un contesto in cui il thread principale
di un'applicazione dispone di una Windows (quindi del realtivo
handle), mi è meno chiaro quando il thread principale è un servizio
(intendo un TService).
In questo caso non si dispone di un handle.
Dalla documentazione ho visto che esiste anche la "PostThreadMessage"
da usare per postare alla coda di un thread, potrei utilizzarla per
inviare messaggi al thread principale (vale a dire il mio servizio) ?
Ed inoltre il thread principale crea la coda o devo farlo io?
Grazie per l'eventuale risposta.
Ciao

Ed inoltre il thread principale crea la coda o devo farlo io?
La coda di messaggi di un thread va creata con un loop di
PostThreadMessage() passando WM_NULL sino a che la funzione non
restituisce TRUE.