2012-04-05 7 views
3

In der Daemon-Klasse Beispiel, die ich implementieren, wird Deskriptoren Umleitung verwendet.Datei-Deskriptoren Umleitung ist fest

sys.stdout.flush()      
sys.stderr.flush()      
si = file(self.stdin, 'r')    
so = file(self.stdout, 'a+')    
se = file(self.stderr, 'a+', 0)   
os.dup2(si.fileno(), sys.stdin.fileno()) 
os.dup2(so.fileno(), sys.stdout.fileno()) # This line doesn't work 
os.dup2(se.fileno(), sys.stderr.fileno()) 

os.dup2(so.fileno(), sys.stdout.fileno()) funktioniert nicht. Es verursacht keine Fehler. Der Code nach dieser Zeile wird nicht ausgeführt.

ich vereinfachte dieses Beispiel auf die Klasse nur der Problembereich enthält:

class Deamon(object): 
    def __init__(self, pidfile, stdout='/dev/null'): 
     self.pidfile = pidfile 
     self.stdout = stdout 
    def get_stdout(self): 
     so = file(self.stdout, 'a+') 
     os.dup2(so.fileno(), sys.stdout.fileno()) 
     print 'executed' 

Nach os.dup2(so.fileno(), sys.stdout.fileno()) Code gerade stecken. Warum passiert es?

bearbeiten (mit @ C2H5OH Code-Implementierung):

try:               
     pid = os.fork()            
     if pid > 0:             
      # exit first parent          
      sys.exit(0)            
    except OSError, e:            
     sys.stderr.write(           
       'fork #1 failed: %d (%s)\n' % (e.errno, e.stderror) 
       )             
     sys.exit(1)             

    os.chdir("/")             
    os.setsid()              
    os.umask(0)              


    try:               
     pid = os.fork()            
     if pid > 0:             
      # exit from second parent        
      sys.exit(0)            
    except OSError, e:            
     sys.stderr.write(           
       "fork #2 failled: %d (%s)" % (e.errno, e.strrerror) 
       )             
     sys.exit(1)             

    # redirect standart file descriptors       
    os.setsid()              
    sys.stdin.flush()            
    sys.stdout.flush()            
    sys.stderr.flush()            

    dev_null = os.open(os.devnull, os.O_RDWR)      
    os.dup2(dev_null, sys.stdin.fileno())       
    print 'executed 1'            
    os.dup2(dev_null, sys.stdout.fileno())       
    print 'executed 2'            
    os.dup2(dev_null, sys.stderr.fileno())       
    os.close(dev_null)  

    # write pidfile 
    # FIXME: file is not writes!      
    atexit.register(self.delpid)     
    pid = str(os.getpid())      
    file(self.pidfile, 'w+').write("%s\n" % pid) 

Im stop Methode habe ich try-out von self.pidfile vorhanden:

def stop(self):     
    print file(self.pidfile, 'r') 

Dies ist ein Fehler aus:

IOError: [Errno 2] No such file or directory: '/tmp/deamon-example.pid'

Das Problem m ist immer noch da drin.

+0

Übrigens, Python-Dokumentation [empfiehlt, 'open()' anstelle von 'file()'] zu verwenden (http://docs.python.org/library/functions.html#file) – C2H5OH

Antwort

4

Sie mischen Python Datei-Handles mit dem Betriebssystem Dateideskriptoren, das für Probleme fragt: sowieso

Hinzu kommt, dass, sind Sie stdout /dev/null umleiten.

Während Sie richtig sind os.dup2() zur Verwendung von sys.stdout zu umleiten (weil eine direkte Zuordnung nicht vollständig funktionieren kann, wenn andere Module einen Verweis darauf erworben), sollten Sie Dateien öffnen, auf der Betriebssystemebene mit os.open().

Hier ist der daemonization Code, den wir an meinem Arbeitsplatz verwenden:

if os.fork() > 0: 
    os._exit(0) 
os.setsid() 
sys.stdin.flush() 
sys.stdout.flush() 
sys.stderr.flush() 
null = os.open(os.devnull, os.O_RDWR) 
os.dup2(null, sys.stdin.fileno()) 
os.dup2(null, sys.stdout.fileno()) 
os.dup2(null, sys.stderr.fileno()) 
os.close(null) 

Wenn Sie stdout zu einem gewissen Datei umleiten möchten, verwenden Sie einfach einen anderen Dateinamen anstelle der vordefinierten Konstante os.devnull.

+0

Ich versuche, Ihren Vorschlag umzusetzen. Das Problem ist jetzt nicht gelöst. Ist es nach der ersten Verwendung dup2, dev_null schließt? Ist es das Problem? Ich habe zu meiner Post-Implementierung etwas von deinem Code in die Haupt-Daemon-Klasse hinzugefügt. Hilf mir bitte zu lösen und zu verstehen. – I159

+0

Nach dem erneuten Lesen Ihrer Frage, was genau verstehen Sie für _getting stecken_? Woher weißt du, dass die Ausführung nicht über das erste 'dup2()' hinausgeht? Denken Sie daran, dass Sie nach dem Umleiten der Standardausgabe auf "/ dev/null" nichts mehr "drucken" sehen. Um die Ausführung zu verfolgen, sollten Sie sich in einer Datei anmelden. – C2H5OH

+0

Noch einmal habe ich meine Frage geändert. Nachdem der problematische Zeilencode nicht ausgeführt wurde, schreibt die PID-Datei nicht, siehe oben in der Frage. Vielen Dank! – I159

3

http://docs.python.org/library/os.html#os.dup2

Above Dokumentation sagt: os.dup2(fd, fd2) Duplicate file descriptor fd to fd2, closing the latter first if necessary.

Also diese Zeile: os.dup2(so.fileno(), sys.stdout.fileno()) offenbar sys.stdout schließt die effektiv alle Ausgaben heruntergefahren. Der Code erscheint "hängen", aber Sie sehen keine Ausgabe. d.h., es gibt keine Fehler.

def __init__(self, pidfile, stdout='/dev/null'): 
    #... 
    self.stdout = stdout   # <--self.stdout points to /dev/null 
def get_stdout(self): 
    so = file(self.stdout, 'a+') # <-- opening /dev/null for append? 
    # even if the next line worked, you're appending to /dev/null and you wouldn't see any output 
    os.dup2(so.fileno(), sys.stdout.fileno()) 
+0

Ich versuche zu implementieren @ C2H5OH 's Rat und bedenken Sie auch Ihren Rat. 'tmp = tempfile.TemporaryFile() os.dup2 (tmp.fileno(), sys.stdin.fileno()) os.dup2 (tmp.fileno(), sys.stdout.fileno()) os.dup2 (tmp.fileno(), sys.stderr.fileo()) ' > Diese Zeile: os.dup2 (so.fileno(), sys.stdout.fileno) schließt scheinbar sys.stdout. Wie ändere ich dieses Verhalten? – I159

+0

@ I159: Ich weiß nicht, wie ich dieses Verhalten ändern soll. Sie sollten der Antwort von C2H5OH wahrscheinlich mehr Aufmerksamkeit schenken. Es klingt, als hätte er mehr Erfahrung und besseren Einblick. Viel Glück. – alan

+0

Danke Alan! Ich benutzte print-Anweisungen, um ein dämonisches Programm zu verfolgen, und sie stoppten nach der Zeile os.dup2 (so.fileno(), sys.stdout.fileno()). Ich schrieb danach direkt in eine Log-Datei und konnte sehen, dass das Programm weiter lief! – BuvinJ