MokaByte
Numero 24 - Novembre 98
|
|||
|
|||
Antonio Cisternino |
|
||
In questo articolo mi occuperò di mostrare come sia possibile tramutare in servizio NT un’applicazione Java standalone senza far ricorso alle estensioni del JDK di Microsoft.
Introduzione
In questo articolo
affronterò un aspetto importante dello sviluppo di server in Java:
la possibilità di renderli dei servizi su Windows NT. Descriverò
una soluzione shareware offerta da IQX e successivamente una soluzione
basata su un sorgente C da me modificato e liberamente utilizzabile.
In tutto l’articolo
Java sarà un po’ a margine poiché il servizio vero e proprio
è realizzato in C. L’obiettivo dell’articolo non è
comunque quello di descrivere in modo esauriente lo sviluppo di un servizio
per Windows NT, bensì quello di illustrare le problematiche dei
servizi di NT relative all’attivazione di un server scritto in Java.
Un’interessante
evoluzione del codice qui presentato potrebbe essere una libreria JNI che
permetta di amministrare il servizio direttamente da Java utilizzando le
funzioni presentate.
Perché usare un servizio NT?
Chiunque sia
abituato a lavorare su Unix o Linux si stupisce nello scoprire che su Windows
NT non è disponibile un meccanismo simile al nohup. Contrariamente
a quanto accade su Unix infatti in Windows NT quando un utente si disconnette
il sistema si preoccupa di terminare tutti i processi di quell’utente impedendo
quindi di lasciare un server attivo. Per ottenere lo stesso risultato del
demone Unix su Windows NT è necessario scrivere un programma oppure
usarne uno già scritto che semplicemente permette di parametrizzare
l’applicazione da lanciare. La funzione di questo programma è di
registrare, usando opportune chiamate di sistema, un’applicazione come
servizio. Una volta installato un servizio può essere avviato o
arrestato tramite l’apposito applet nel pannello di controllo di Windows.
Il Service Control Manager (SCM) si occupa di amministrare i servizi utilizzando
un apposito database in cui memorizza le informazioni relative ad ogni
servizio correntemente disponibile nel sistema. Per poter aggiungere un
nuovo servizio si chiamano apposite API che ne permettono la registrazione.
Service Runner
Il service runner
è un’applicazione shareware sviluppata da IQX che si propone appunto
come obiettivo quello di trasformare in servizio NT qualsiasi eseguibile
per Windows. Questa applicazione, disponibile all’URL http://www.iqx.com/corporate/,
può essere utilizzata liberamente per fini non commerciali. Descriverò
innanzitutto il suo funzionamento e successivamente, una volta introdotto
il codice valuteremo come può essere implementato lo stesso applicativo
partendo da quanto sviluppato.La prima caratteristica di service runner
è quella di funzionare come processo generatore di altri processi
che sono gli applicativi che vanno realmente eseguiti come servizio. In
pratica è un sistema per avere una specie di comando che permetta
di lasciare un processo in background anche dopo il logoff.
Il servizio
installato è quindi service runner ed è il server che avvierà
i vari processi gestendoli opportunamente. Per installare il servizio sarà
sufficiente eseguire il comando
ServiceRunner –installSuccessivamente tramite il pannello di controllo oppure il prompt del DOS usando il comando
net start ServiceRunnersi può far partire il servizio. Una volta avviato il servizio è sufficiente utilizzare il comando
ServiceLaunch <executable> <arg1> <arg2> ...dove <executable> è il nome del comando da eseguire e <arg1>, <arg2>, … sono gli argomenti della riga di comando da passare all’applicazione.
ServiceLaunch server.batLa necessità di impostare le variabili d’ambiente deriva dal fatto che un servizio non gira solitamente come processo dell’utente che lo ha lanciato bensì come utente di un account particolare dedicato all’esecuzione dei servizi. Capita quindi che le impostazioni dell’ambiente relativi all’utente non siano disponibili nell’account System utilizzato per eseguire il servizio.
Il nostro servizio
Una volta descritta
un’applicazione commerciale vediamo come sia possibile scrivere un servizio
per Windows NT utilizzando il linguaggio C e la Win32. Il codice che descriverò
è alla terza revisione: il codice di base è disponibile tra
gli esempi forniti con l’SDK di Microsoft, successivamente un certo Dean
Troyer lo ha esteso rendendolo parametrico ed infine io l’ho ulteriormente
ritoccato aggiungendo funzionalità minori.
Trovo che questo
programma sia di una semplicità disarmante, data la complessità
dell’operazione, e soprattutto che sia ancora parametrizzabile per realizzare
un’applicazione che offra le stesse funzionalità di service runner
risolvendo entrambi i problemi elencati. D’altra parte è ridicolo
che in un sistema operativo di rete sia così complicato mettere
in esecuzione dei processi in background: capita spesso di aver necessità
di lasciare un processo a lavorare, anche per giorni, per non parlare poi
dei server custom che spesso si sviluppano per far pronte alle proprie
esigenze.
Se il nome dell’eseguibile
del nostro servizio è service.exe allora il comando
esegue il servizio come una normale applicazione per vedere se tutto funziona.
service –installregistra il servizio presso il SCM; il comando
service –removeelimina il servizio dal database dei servizi; il comando
service –debug
La funzione main
del programma in questione si comporta solo come dispatcher di servizio
e, dopo aver deciso in base ai parametri passati sulla riga di comando,
chiama una funzione apposita. Prenderemo successivamente in considerazione
l’azione intrapresa nel caso in cui nessuno switch sia stato specificato
o riconosciuto.
Le funzioni
associate ai relativi switch sono: CmdInstallService, CmdRemoveService,
CmdHelp e CmdDebugService. Ovviamente le due funzioni interessanti da prendere
in considerazione sono le prime due poiché mostrano come sia possibile
registrare e eliminare un servizio presso il SCM. Per comprendere il funzionamento
di base dei servizi resterà infine da analizzare l’avvio e l’arresto
di un servizio.
Come ho già
detto il modulo di NT responsabile della gestione dei servizi è
il Service Control Manager, per poter operare con questo modulo è
necessario collegarsi utilizzando la chiamata di sistema
OpenSCManager(...)Una volta ottenuta una handle al manager dei servizi è possibile installare un servizio usando la chiamata di sistema
CreateService(...)La creazione del servizio comporta, da parte dell’SCM, la registrazione dell’eseguibile che ha eseguito la chiamata di sistema presso il database dei servizi. All’atto della creazione del servizio vengono poi specificate alcune informazioni che il SCM userà per fornire informazioni all’utente tramite l’applet dei servizi nel pannello di controllo.
L’eliminazione di un servizio segue, in linea di principio, lo stesso schema dell’installazione: si ottiene una handle al SCM e successivamente una handle al servizio utilizzando la chiamata di sistema
CloseServiceHandle(...)
OpenService(...)infine si utilizza la handle così ottenuta per invocare la chiamata
DeleteService(...)che elimina il servizio dal database del SCM. C’è un’unica anche se non banale differenza tra la funzione che installa il servizio e quella che lo elimina: quando viene richiesta la rimozione il servizio potrebbe essere attivo e va quindi arrestato prima di procedere all’eliminazione. Per questo motivo, una volta ottenuta una handle al servizio si usa la funzione
per richiedere l’arresto del servizio e si attende, con un ciclo di polling che questo sia effettivamente terminato controllando lo stato ogni secondo usando la funzione apposita
ControlService(...)
QueryServiceStatus(...)Una volta arrestato il servizio si può procedere all’eliminazione usando la chiamata DeleteService.
StartServiceCtrlDispatcherA questa funzione viene passata una tabella di servizi, che in questo caso contiene una sola riga, in cui viene associato al nome del servizio la funzione che verrà invocata come punto di inizio dell’esecuzione del servizio. Nel nostro caso questa funzione è la funzione service_main.
Java, IQX e i servizi NT
Sfruttando il
codice allegato all’articolo è possibile ridefinire le funzioni
ServiceStart, ServiceInstall, ServiceRemove e ServiceStop, chiamate opportunamente
dal codice C che si interfaccia realmente a Service Control Manager.
Se la StartService
si occupa di lanciare un processo e poi di aspettarne la terminazione si
comporta correttamente secondo il significato del metodo in questione.
Per Java è quindi necessario assicurarsi che le variabili d’ambiente
siano definite per l’utente System, successivamente, mediante una chiamata
alla funzione
CreateProcess(...)
È possibile
lanciare la JVM che comincia ad assolvere il servizio stesso. Per impedire
però che la funzione ServiceStart termini, e quindi che il resto
del codice consideri terminato il servizio, è necessario ricorrere
alla funzione
WaitForSingleObject(...)
Che sospende
l’esecuzione del codice corrente finché il processo creato non è
morto.
Nel caso di
IQX il programma ServiceRunner è semplicemente un servizio come
quello illustrato in questo articolo ed è capace di eseguire più
processi contemporaneamente. In questo caso non è però possibile
distinguere tra i vari servizi che si attivano mentre utilizzando il codice
presentato in questo articolo è possibile controllare ogni applicazione
come singolo servizio.
Conclusioni
In questo articolo
ho presentato la struttura C di un servizio per Windows NT. Ho mostrato
che esistono alternative commerciali e che sono tutti più o meno
uguali a quello presentato.
Abbiamo visto
quali funzioni della API 32 di Windows sono necessarie per interagire con
il SCM.
Infine abbiamo
discusso su come sia possibile eseguire Java come Servizio.
Allegato
Per concludere
ecco i sorgenti con cui mettere in pratica quanto
detto fino ad ora.
MokaByte Web 1998 - www.mokabyte.it MokaByte ricerca nuovi collaboratori. Chi volesse mettersi in contatto con noi può farlo scrivendo a mokainfo@mokabyte.it |