Un Python demoniaco alla fermata del bus!

I miei studi sul Python proseguono a gonfie vele e oggi vi presento un piccolo HOWTO su come scrivere un demone nel linguaggio di programmazione più portabile del mondo (e a chi, in questo momento, viene in mente solo la parola Java dico: “Seee! Te piacerebbe!“).

Andiamo per gradi, iniziamo a rispondere alla prima domanda: cos’è un demone? Cito Wikipedia:

Nei sistemi Unix, e più in generale nei sistemi operativi multitasking, un demone (daemon in inglese) è un programma eseguito in background, senza che sia sotto il controllo diretto dell’utente. Di solito i demoni hanno nomi che finiscono per “d”: per esempio, syslogd è il demone che gestisce i log di sistema.

In ambiente Windows un tale programma è noto con il nome di Servizio.

Angeli e diavoli

Insomma, un demone è un applicazione residente in memoria che può avere, come compiti principali, quello di rispondere a delle richieste da parte di altri programmi e/o eseguire periodicamente delle procedure; questo tipo di soluzione è molto utile nel caso si intenda sviluppare un’applicazione distribuita secondo un modello client/server e nel seguente esempio verrà implementato un piccolo demone, il quale avrà come unico scopo quello di rispondere alle richieste ricevute tramite DBus, il bus di sistema di GNOME. Se pensate che possa essere un compito difficile, ve ne farò ricredere!

Ok, siamo pronti, cominciamo: innanzitutto entriamo nella nostra Home e creiamoci una cartella dove andremo a posizionare i sorgenti:

cd ~

mkdir test

Dunque creiamo il file che conterrà il codice del nostro infernale componente software:

gedit ~/test/daemon.py

Ecco fatto! Ora non resta che copiare e incollare all’interno dell’editor il seguente codice, al cui interno ho già inserito numerosi commenti, i quali, grazie anche all’estrema semplicità del linguaggio, saranno sicuramente più che sufficienti per comprendere il funzionamento del demone:

#!/usr/bin/env python

# File: daemon.py

# Spostiamoci nella directory corrente

import os,sys

if __name__ == ‘__main__’:

os.chdir(os.path.dirname(os.path.normpath(os.path.join(os.getcwd(),sys.argv[0]))))

# Importiamo i moduli necessari

import gobject

import dbus

import dbus.service

if getattr(dbus, ‘version’, (0,0,0)) >= (0,41,0):

import dbus.glib

LOG_DIR = ‘/tmp’ # Questa ci serve per memorizzare il file .pid

# Il nostro oggetto condiviso

class Demone(dbus.service.Object):

def __init__(self, bus_name, object_path=’/org/test/daemon’):

# è necessario richiamare il costruttore della classe base

dbus.service.Object.__init__(self, bus_name, object_path)

## Eccoci ad un punto saliente finalmente!

## Questo "stupido" metodo, che verrà richiama dalla nostra

## applicazione, fa solo una cosa: stampa a schermo un

## simpatico saluto (strano per un *demone*, vi pare?).

@dbus.service.method(‘org.test.daemon.prova’)

def Hello(self):

sys.stdout.write(‘Hello world from a dbus daemon!\n’)

sys.stdout.flush()

return 0

#end function Hello

############## SIGNAL HANDLERS #################

## Qui raccogliamo tutti i metodi che gestiranno i segnali ricevuti.

## In questo caso ci interessa gestire solo SIGTERM.

def terminate(signal, param):

try:

# Esegue tutte le operazioni necessarie alla corretta

# chiusura dell’applicazione

# Cancella il file .pid

os.remove(os.path.join(LOG_DIR, ‘run.pid’))

except:

pass # Ignora tutti gli errori…

## …e stampa un messaggio di addio!

sys.stdout.write("……..terminating\n")

sys.exit(0)

############## END SIGNAL HANDLERS ##############

## Analizza e restituisce lo stato attuale del demone (se è attivo

## o meno). Restituisce il process id del demone se è attualmente

## presente in memoria, -1 in caso contrario.

def status():

if os.path.isfile(os.path.join(LOG_DIR, ‘run.pid’)):

f = open(os.path.join(LOG_DIR, ‘run.pid’), ‘r’)

pid = string.atoi(string.strip(f.readline()))

f.close()

try:

os.kill(pid, 0)

except os.error, args:

if args[0] != errno.ESRCH: # Nessun processo

raise os.error, args

else:

# il demone è avviato

return pid

# il demone non è presente in memoria

return -1

## Quelle che seguono sono le istruzioni relative alla gestione

Page 1 of 3 | Next page