2012-04-05 126 views
3

在我实现的守护程序类示例中,使用描述符重定向。重定向的文件描述符被卡住

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())不起作用。它不会引发错误。该行之后的代码未执行。

我简化了这个例子的类仅包含问题区域:

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' 

os.dup2(so.fileno(), sys.stdout.fileno())代码只是卡住了。 为什么会发生?

编辑(以@ C2H5OH代码执行):

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) 

stop方法我已经尝试出的self.pidfile现有:

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

这是引发错误:

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

该问题米仍然在那里。

+0

顺便说一句,Python文档[建议使用'open()'而不是'file()'](http://docs.python.org/library/functions.html#file) – C2H5OH 2012-04-06 16:09:25

回答

4

你混合的Python文件与操作系统文件描述符处理,这是自找麻烦。

当你使用os.dup2()重定向sys.stdout(因为直接分配可能不会完全正常工作,如果其他模块的采集对它的引用),你应该可以用os.open()操作系统级打开的文件正确。

下面是我们在我的工作场所使用的系统守护进程代码:

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) 

如果你想标准输出重定向到一些文件,只是使用不同的文件名,而不是预定义的常量os.devnull

+0

我尝试实施您的建议。问题现在没有解决。第一次使用dup2后,dev_null关闭了吗?这是问题吗?我在后期实现中添加了一些代码给主守护进程类。请帮助我解决和理解。 – I159 2012-04-06 07:25:42

+0

重新阅读您的问题后,您对_getting stuck_的理解到底是什么?你怎么知道执行没有超出第一个'dup2()'?请记住,一旦将标准输出重定向到'/ dev/null',您将看不到任何'print'-ed。为了追踪执行情况,您应该记录到一个文件。 – C2H5OH 2012-04-06 10:41:06

+0

再一次,我改变了我的问题。有问题的行代码没有执行之后,pidfile不是写入操作,请参阅上面的问题。非常感谢! – I159 2012-04-06 14:21:56

3

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

以上的文件说:os.dup2(fd, fd2) Duplicate file descriptor fd to fd2, closing the latter first if necessary.

所以这行: os.dup2(so.fileno(), sys.stdout.fileno()) 显然是关闭sys.stdout有效地关闭所有输出。代码显示“卡住”,但你只是没有看到任何输出。即没有错误。

最重要的是,你要重定向标准输出到/dev/null反正:

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

我尝试实现@ C2H5OH的建议也考虑你的建议。 'tmp = tempfile.TemporaryFile() os.dup2(tmp.fileno(),sys.stdin.fileno()) os.dup2(tmp.fileno(),sys.stdout.fileno()) os.dup2 (tmp.fileno(),sys.stderr.fileno())' >所以这行:os.dup2(so.fileno(),sys.stdout.fileno())显然是关闭sys.stdout。如何改变这种行为? – I159 2012-04-05 20:38:20

+0

@ I159:我不知道如何改变这种行为。您应该更加关注C2H5OH的答案。这听起来像他有更多的经验和更好的见解。祝你好运。 – alan 2012-04-05 21:07:52

+0

谢谢阿兰!我使用print语句来跟踪守护程序,并且它们在os.dup2(so.fileno(),sys.stdout.fileno())之后停止。之后我直接写了一个日志文件,可以看到程序继续运行! – BuvinJ 2015-08-05 22:42:55