Domanda

Sto provando a eseguire tclhttpd in un interprete slave ma leggermente modificato per essere eseguito all'interno un tclkit. Il codice qui sotto "esegue" (Posso premere http: // localhost: 8015 ) ma non raggiungo mai la riga in fondo perché " il server non ritorna, entra [vwait forever] " ;. Ma quando provo " il trucco dopo 0 " ;, ad es. prepending "dopo 0" alla riga "$ httpd eval $ cmd", il server non funziona affatto, quindi presumo che gli errori "debbano essere gestiti da bgerror"

Tuttavia non riesco a trovare buoni esempi su come usare bgerror, inoltre la mia ricerca mostra che ora la convenzione è di usare "interp bgerror". Consulta i primi due esempi restituiti da http://www2.tcl.tk/_ / gsearch S = bgerror ?; il primo link contiene la verbosità "compilare utili trucchi ed esempi per l'utilizzo di bgerror" ma poi non ci sono campioni che riesco a discernere come applicare, e il secondo link conclude "Sono interessato agli esempi su come dovrebbe essere usato questo".

package require starkit
starkit::startup

set httpd_args [list]
set httpd [interp create]
$httpd eval "set argc [llength $httpd_args]"
set cmdargv "set argv [list $httpd_args ]"
$httpd eval "set topdir $starkit::topdir"
$httpd eval $cmdargv

set cmd [list source [file join $starkit::topdir bin/httpd.tcl]]
$httpd eval $cmd

puts "if seeing this controlled has returned"
È stato utile?

Soluzione

Non capisco bene la domanda che stai ponendo. Sembra che il tuo obiettivo sia quello di avviare un server http in un interprete ma in qualche modo interagire con l'interprete principale. È giusto? In tal caso, cosa c'entra questo con bgerror?

Sei consapevole del fatto che anche se stai eseguendo il server in un interprete separato, non è in esecuzione in un thread separato? Cioè, non è possibile (*) interagire con l'interprete principale mentre uno dei due interpreti è bloccato da un vwait.

(*) puoi, se la tua interazione assume la forma di widget Tk che sfruttano anche il ciclo degli eventi

Per quanto riguarda come usare bgerror, ci sono un paio di modi in cui funziona. Il meccanismo predefinito chiama la funzione 'bgerror " che puoi definire per fare quello che vuoi. Prende una singola stringa (il testo di un messaggio di errore) e fa qualcosa con esso. Quel qualcosa potrebbe essere quello di stampare l'errore su stdout, mostrarlo in una finestra di dialogo, scriverlo su un file, ecc.

Ad esempio, considera questa sessione interattiva:

% proc bgerror {s} {puts "hey! I caught an error: $s"}
% # after 30 seconds, throw an error
% after 30000 {error "this is an error"}
after#0
% # after 40 seconds, terminate the event loop
% after 40000 {set ::done 1}
after#1
% # start the event loop
% vwait ::done
hey! I caught an error: this is an error
% # this prompt appears after 40 seconds or so

Puoi anche registrare il tuo gestore degli errori, come descritto nella documentazione di "interp bgerror". Ciò è avvenuto nella tcl 8.5, sebbene avesse un bug che non è stato corretto fino alla 8.5.3.

Ad esempio:

% set foo [interp create]
interp0
% $foo eval {proc myErrorHandler {args} {puts "myErrorHandler: $args"}}
% $foo bgerror myErrorHandler
myErrorHandler
% # after 30 seconds, throw an error
% $foo eval {after 30000 {error "this is an error"}}
after#0
% # after 40 seconds, terminate the loop
% $foo eval {after 40000 {set ::done 1}}
after#1
% $foo eval {vwait ::done}
myErrorHandler: {this is an error} {-code 1 -level 0 -errorcode NONE -errorinfo {this is an error
    while executing
"error "this is an error""
    ("after" script)} -errorline 1}
% # this prompt appears after 40 seconds or so

Questo aiuta a rispondere alla tua domanda?

Altri suggerimenti

Completamente modificato in base ai commenti del PO ...

Il trucco dopo 0 è la seguente riga:

after 0 $httpd eval $cmd

Ciò che fa è dire all'interp di aggiungere il comando in questione ($ http eval $ cmd) alla coda degli eventi, il che significa che verrà eseguito una volta avviato il ciclo degli eventi (o ripristinato se è già avviato). Puoi vedere la dipendenza dal loop degli eventi nel seguente commento da quella pagina (di Jacob Levy):

  

Dovrei notare che questo dipende dal fatto che il ciclo di eventi sia attivo.

La mia ipotesi è che stai eseguendo un semplice Tclsh, il che significa che non entri mai nel loop degli eventi (la shell Wish entra nel loop degli eventi alla fine dello script, la shell Tcl no). Il modo standard per accedere al ciclo degli eventi è eseguire il comando seguente una volta arrivato alla fine del codice Tcl:

# Enter the event loop and stay in it until someone 
# sets the "forever" variable to something
vwait forever

Detto questo, tutto ciò che hai dopo la vwait non verrà eseguito fino a quando non verrà chiuso il loop degli eventi. Se vuoi che httpd venga eseguito in parallelo al tuo codice, devi:

  • Usa più thread o scrivi il tuo ... che non è poi così difficile
  • il codice deve essere basato su eventi ... il che richiede che tu capisca anche la programmazione basata abbastanza bene da evitare che parti di codice siano prive di tempo di esecuzione.

Spero che sia d'aiuto.

Se ho capito bene cosa vuoi fare, il tuo codice dovrebbe essere simile a quello:

set httpd_id [thread::create -preserved]
thread::send $http_id "source [file join $starkit::topdir bin/httpd.tcl]"

In questo modo avrai TclHttpd in esecuzione in un thread, senza preoccuparti del problema vwait

Se si desidera essere informati anche di eventuali errori durante l'esecuzione di httpd, TclHttp invia tutti gli errori a un file di registro. È possibile configurare il percorso del registro facendo:

Log_SetFile "/logs/httpd_log"

Devi avere il pacchetto httpd :: log.

Spero che questo aiuti.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top