PDA

Visualizza la versione completa : [Delphi] Problema http server


Jey
29-07-2013, 13:27
Buongiorno a tutti,

sto sviluppando un applicativo delphi che faccia da server http utilizzando il componente TIdHTTPServer.
In parallelo sto sviluppando anche un'interfaccia web che richiede i dati al mio server tramite chiamate ajax.

Per esser certi che il server sia attivo, lato client effettuo una chiamata ogni secondo ( watchdog ) che, in caso di esito negativo, evita di effettuare le altre chiamate fino a che non ritorna attivo il server.

Il sistema funziona abbastanza bene, ma ho avuto alcuni problemi quali:

1) Se spengo il server, appena lo riavvio è come se "scodasse" tutte le richieste ( watchdog ) fatte dai miei client e mi ritrovo quindi l'applicativo che accumula thread su thread;

2) Dopo un po' di ore ( dalle 7 alle 9 ore circa ), l'applicativo crasha ( anche se ho try...except ovunque ) e mi esce il messaggio di windows "Application.exe has stopped working ecc". :dhò:

Sbaglio qualcosa io nelle impostazioni del server/client o è il componente che uso che non è ottimale? :confused:

alka
30-07-2013, 11:35
A mio avviso, per approfondire la questione si dovrebbe analizzare quali sono gli strumenti che usi lato client per interrogare il tuo server, quali sono grossomodo le operazioni che svolge e come viene gestita in generale la comunicazione tra le due parti.

Non avendo specificato nessuno di questi dettagli, diventa difficile risalire alle cause dei problemi che hai descritto; ad esempio, è praticamente impossibile dirti quale sia l'origine del crash del tuo server senza sapere cosa fa e come è stato realizzato, in pratica senza un minimo esempio di codice che ne mostri in parte l'architettura.

Prova magari ad aggiungere qualche dettaglio in più.

Ciao! :ciauz:

Jey
30-07-2013, 12:40
Ok ecco un po' di codice allora:



procedure TCommonHttpServer.lpExecute(loRequestInfo: TIdHTTPRequestInfo; loResponseInfo: TIdHTTPResponseInfo);
var
loObj : TCommonAjaxMethod;
loInputJson : TJSONObject;
loOutputJson : TJSONObject;
loStringStream : TStringStream;
loCompressor : TIdCompressorZLib;
lsErrorString : string;
begin
// AGU Init variables
loInputJson := nil;
loStringStream := nil;
loCompressor := nil;
loObj := nil;
try
if (poMethodList.Count > 0) then
begin
if poMethodList.TryGetValue(loRequestInfo.URI,loObj) then
begin
with loResponseInfo do
begin
CustomHeaders.AddValue('Access-Control-Allow-Origin', '*');
if (loRequestInfo.CommandType = hcOPTION) then
begin
CustomHeaders.AddValue('Access-Control-Allow-Methods', 'GET,POST');
CustomHeaders.AddValue('Access-Control-Allow-Headers', 'Content-Type, Accept');
CustomHeaders.AddValue('Access-Control-Max-Age', '1728000');
end;
ContentEncoding := 'utf-8';
ContentType := 'application/json; charset=utf-8';
loInputJson := TJSONObject(TJSONObject.ParseJSONValue(loRequestIn fo.Params.Text));
loOutputJson := loObj(loInputJson);
loStringStream := TStringStream.Create(loOutputJson.ToString);
loCompressor := TIdCompressorZLib.Create(nil);
ContentStream := TMemoryStream.Create;
loCompressor.CompressStream(loStringStream, ContentStream, 9, GZIP_WINBITS, 9, 0);
ContentEncoding := 'gzip';
ContentLength := ContentStream.Size;
end;
end;
end;
except on E : Exception do
end;
if Assigned(loInputJson) then FreeAndNil(loInputJson);
if Assigned(loStringStream) then FreeAndNil(loStringStream);
if Assigned(loCompressor) then FreeAndNil(loCompressor);
if Assigned(loOutputJson) then FreeAndNil(loOutputJson);
end;


Questo è il metodo che viene chiamato all'evento OnCommandGet e OnCommandOther dell'oggetto TIdHTTPServer.

Il mio oggetto poMethodList è una TDictionary contenente nome del metodo da chiamare e metodo da chiamare ( TCommonAjaxMethod ).
Quest'ultimo è così definito:



TCommonAjaxMethod = function(loJson: TJSONObject): TJSONObject of object;


Le chiamate lato client invece sono così:



ServerMgrClass.prototype.SendPostRequest = function( lsUrl, lbAsync, lsDataType, loJson, lsMethodName, loOnSuccess, loOnError, loDefaultResult, liTimeout ){
lsUrl = lsUrl == undefined ? this.Url : lsUrl;
if( !loJson ){
loJson = {};
}
loJson.isEnglish = false;
loJson.sessionId = ( loJson.sessionId != undefined ) ? loJson.sessionId : this.SessionId ;
var loResult = loDefaultResult;
if( this.IsAlive ){
with( this ){
$.ajax({
type : "POST",
data : encodeURIComponent( JSON.stringify( loJson ) ),
dataType : lsDataType ? lsDataType : "json",
async : lbAsync,
timeout : ( liTimeout ? liTimeout : 5000 ),
url : lsUrl + lsMethodName,
success : function( data ){
if( loOnSuccess ){
loOnSuccess( data );
}
if( !lbAsync ){
try{
loResult = data;
}
catch( e ){
loResult = null;
}
}
},
error : function(e){
if( loOnError ){
loOnError();
}
}
});
}
}
else{
if( loOnError ){
loOnError();
}
}
return loResult;
}


Mentre quest'ultimo è il timer di watchdog:



...
...

with( this ){
this.Watchdog = setInterval(function(){
$.ajax( {
type : "POST",
data : JSON.stringify( {} ),
dataType : "json",
async : true,
timeout : 2000,
processData : false,
url : Url + "WatchDog",
success : function( data ){
IsAlive = true;
LastResponse = new Date( data.localTime );
document.getElementById( "indexDivTimeBar" ).innerHTML = LastResponse.format( "dd/mm/yyyy HH:MM:ss" );
},
error : function(){
IsAlive = false;
}
});
}, 1000);
}

...
...

denis76
30-07-2013, 21:01
Ciao, uso da anni questo componentei n un programma attivo h24 e non ho mai avuto problemi. Assicurati di liberare bene la ram.

Ciao ciao.

alka
31-07-2013, 18:49
Ottimo per il codice, che direi fornisce un dettaglio già più preciso delle operazioni che vengono effettuate.

In generale, non ho riscontrato grossi problemi con Indy, anche se va detto che in alcune versioni possono trovarsi dei fastidiosi buchi che dipendono anche dai componenti usati.

Secondo me, inizierei a dotare l'applicazione di un log per tenere traccia di quello che accade, magari lasciandolo in esecuzione per una nottata; dal lato client, proverei a installare l'estensione Firebug su Firefox/Chrome per monitorare le richieste che vengono inviate e le corrispondenti risposte, verificando ad esempio perché queste si accumulano e sono reiterate pur scollegando il server.

Ciao! :ciauz:

Jey
02-08-2013, 13:36
Grazie per le risposte, ho fatto un po' di log ma non ho avuto grandi successi.

Ho notato però che le chiamate non si accodano ( visualizzo sulla form il numero di richieste che ricevo e all'avvio non vedo incrementare il numero a raffica ) e in più ho notato anche che tende ad accumulare thread quando sono in una certa pagina del mio sito ( che fa sulle 10 richieste asincrone contemporanee ) con vari client accesi ( 15 client da pc diversi ), quindi può essere che si incasini per problemi miei e non del componente :mem:

Mi rimane da risolvere il crash... Non vorrei che accedo, da qualche parte, a qualche oggetto privato da più thread insieme e questo crei casino, anche se dovrei aver messo una critical section ovunque usi oggetti privati di una classe... :dhò:

Per quanto riguarda il liberare la ram invece non credo sia quello perchè l'occupazione mi rimane stabile anche dopo parecchie ore ( testandolo con 1 client non l'ho visto crashare neanche dopo giorni )

Loading