Python:fork()之后奇怪的stdout行为

Python:fork()之后奇怪的stdout行为,python,fork,stdout,daemon,Python,Fork,Stdout,Daemon,我正在开发一个python程序,其中包含一个为不同用户和服务启动子进程的守护进程。 以下是感兴趣的代码: ''' Created on 13.02.2014 @author: Richard Neumann ''' import os, zmq, signal, threading, time, sys from homie import Syslog, Config from homie.lib.files import FieldsFile from homie.service impo

我正在开发一个python程序,其中包含一个为不同用户和服务启动子进程的守护进程。 以下是感兴趣的代码:

'''
Created on 13.02.2014

@author: Richard Neumann
'''

import os, zmq, signal, threading, time, sys
from homie import Syslog, Config
from homie.lib.files import FieldsFile
from homie.service import Service
from homie.lib.user import User
from homie.lib.log import LogLvl, ErrLvl, LogEntry
from homie.lib.ipc import SocketClient

class Daemon():
    '''
    Class to represent the system service
    '''        
    def __get_user(self, user_name):
        '''
        Gets a user securely
        '''
        user = False
        try:
            user = User(user_name)
        except:
            self.log('No such user "' + user_name + '"', LogLvl.DEFAULT, ErrLvl.ERROR) 
        return user 

    def __get_service_data(self, user, service_name):
        '''
        Returns the PID and the listening port of a service of a user
        '''
        service_data = user.get_runfile().get_data(service_name)

        ''' Runfile file contains "<service_name>=<pid>[tab]<port>" ''' 
        service_data = service_data.split('\t')

        pid = service_data[0] if len(service_data) >= 1 else None
        port = service_data[1] if len(service_data) >= 2 else None

        return pid, port  

    def __get_pid(self, user, service_name):
        '''
        Returns the PID of a service of a user
        '''
        pid, __ = self.__get_service_data(user, service_name)

        if pid:
            try:
                pid = int(pid)
                return pid
            except:
                self.log('No PID for service "' + service_name + '" for user "' + str(user) + '"', LogLvl.DEFAULT, ErrLvl.ERROR) 
        return None

    def __get_port(self, user, service_name):
        '''
        Returns the listening port of a service of a user
        '''
        __, port = self.__get_service_data(user, service_name)

        if port:
            try:
                port = int(port)
                return port
            except:
                self.log('No listening port for service "' + service_name + '" for user "' + str(user) + '"', LogLvl.DEFAULT, ErrLvl.ERROR) 
        return None

    def __start(self, user_name, service_name):
        '''
        Starts a service for a user
        '''
        print('Starting service "' + service_name + '" for user "' + user_name + '"\t\t'),

        if self.__status(user_name, service_name):
            ''' Service is already running for user '''
            print('[ALREADY RUNNING]')
            return True
        else:
            user = self.__get_user(user_name)
            if user:
                ''' We have a valid user '''
                if service_name in user.get_services():
                    ''' The service is enabled for the user '''
                    try:
                        ServiceClass = Service.by_classname(service_name)
                    except:
                        print('[NO SUCH SERVICE]')
                        return False                      
                    pid = os.fork()
                    if pid != 0:
                        ''' Daemon: Return OK '''
                        print('[OK]')
                        return True
                    else:
                        ''' Child: Start new service '''
                        os.setuid(user.get_uid())   # Do this first!
                        service_instance = ServiceClass(user)
                        service_instance.init()
                        service_instance.start()
                        return True
                else:
                    print('[NOT ENABLED]')
                    return False
            else:
                print('[NO SUCH USER]')
                return False
        print('[FAILED]')
        return False                    

    def __stop(self, user_name, service_name):
        '''
        Stops a service for a user
        '''
        print('Stopping service "' + service_name + '" for user "' + user_name + '"\t\t'),

        if self.__status(user_name, service_name):
            pid = self.__get_pid(self.__get_user(user_name), service_name)

            ''' Kill the process '''
            try:
                os.kill(pid, signal.SIGTERM)

                ''' And remove runfile entry '''
                user = self.__get_user(user_name)
                runfile = user.get_runfile()
                runfile.remove(service_name)

                print('[OK]')
                return True

            except:
                print('[FAILED]')
                return False
        else:
            print('[NOT RUNNING]')
            return True


    def __status(self, user_name, service_name, quiet=True):
        '''
        Determines status of the daemon
        '''
        if not quiet: print('Service "' + service_name + '" for user "' + user_name + '" is\t\t'), 

        user = self.__get_user(user_name)
        if user:
            pid = self.__get_pid(user, service_name)
            try:
                os.kill(pid, 0)
                status = '[UP'

                try:
                    port = self.__get_port(self.__get_user(user_name), service_name)
                    sc = SocketClient(port)
                    if sc.query('status') == 'RUNNING':
                        status += ' & RUNNING]'
                    else:
                        status += ' & STOPPED]'
                except:
                    status += ' & UNDETERMINED]'

                if not quiet: print(status)

            except:
                if not quiet: print('[DOWN]')
                return False
            return True
        else:
            if not quiet: print('[NO SUCH USER]')
            return False


    def start(self, user_name=None, service_name=None):
        '''
        Starts the daemons
        '''
        if user_name:
            ''' Start user's services '''
            if service_name:
                self.__start(user_name, service_name)    
            else:
                user = self.__get_user(user_name)
                if user:
                    for service_name in user.get_services():
                        self.start(user_name, service_name)
                else:
                    print('No such user: ' + user_name)
        else:
            for user in User.fetch(Config.CUSTOMERS_GROUP):
                self.start(str(user), service_name)


    def stop(self, user_name=None, service_name=None):
        '''
        Stops the daemons
        '''
        if user_name:
            ''' Start user's services '''
            if service_name:
                self.__stop(user_name, service_name)
            else:
                user = self.__get_user(user_name)
                if user:
                    for service_name in user.get_services():
                        self.stop(user_name, service_name)
                else:
                    print('No such user: ' + user_name)
        else:
            for user in User.fetch(Config.CUSTOMERS_GROUP):
                self.stop(user.get_name(), service_name)

    def status(self, user_name=None, service_name=None):
        '''
        Determines status of the daemons
        '''
        if user_name:
            ''' Start user's services '''
            if service_name:
                self.__status(user_name, service_name, quiet=False)
            else:
                user = self.__get_user(user_name)
                if user:
                    for service_name in user.get_services():
                        self.status(user_name, service_name)
                else:
                    print('No such user: ' + user_name)
        else:
            for user in User.fetch(Config.CUSTOMERS_GROUP):
                self.status(user.get_name(), service_name)

    def restart(self, user_name=None, service_name=None):
        '''
        Restarts the daemons
        '''
        self.stop(user_name, service_name)
        self.start(user_name, service_name)

    def reload(self, user_name=None, service_name=None):
        '''
        Reloads the deamons
        '''
        # TODO: Just reload
        self.restart(user_name, service_name)

    def log(self, message, loglvl, errlvl):
        '''
        Logging
        '''
        entry = LogEntry(self, message, loglvl, errlvl)
        Syslog.log(entry)
我怀疑错误在_start()方法中的某个地方:

但我不明白哪里出了问题。 如果有任何提示,我将不胜感激

问候,


Richard

在调用
os.fork
之前,您应该刷新stdout或任何其他输出流。有很多关于Python中守护进程的有用信息。另外,检查一下这个

看起来您可能在fork之前有未刷新的输出,而在fork之后的两个进程中都会刷新该fork。我没有仔细观察。这通常是分叉时产量加倍的原因
# /etc/init.d/homied start
Starting service "ExposeAgent" for user "test"      [OK]
Starting service "ExposeAgent" for user "test2"     [OK]
Starting service "Someservice" for user "test2"     [NO SUCH SERVICE]
Starting service "ExposeAgent" for user "test3"     [OK]
Starting service "ExposeAgent" for user "test4"     [OK]
Starting service "ExposeAgent" for user "test5"     [OK]
Starting service "ExposeAgent" for user "test6"     [OK]
Starting service "ExposeAgent" for user "test7"     [OK]
Starting service "ExposeAgent" for user "test8"     [OK]
Starting service "ExposeAgent" for user "test9"     [OK]
Starting service "ExposeAgent" for user "test2"     Starting service "Someservice" for user "test2"     [NO SUCH SERVICE]
def __start(self, user_name, service_name):
        '''
        Starts a service for a user
        '''
        print('Starting service "' + service_name + '" for user "' + user_name + '"\t\t'),

        if self.__status(user_name, service_name):
            ''' Service is already running for user '''
            print('[ALREADY RUNNING]')
            return True
        else:
            user = self.__get_user(user_name)
            if user:
                ''' We have a valid user '''
                if service_name in user.get_services():
                    ''' The service is enabled for the user '''
                    try:
                        ServiceClass = Service.by_classname(service_name)
                    except:
                        print('[NO SUCH SERVICE]')
                        return False                      
                    pid = os.fork()
                    if pid != 0:
                        ''' Daemon: Return OK '''
                        print('[OK]')
                        return True
                    else:
                        ''' Child: Start new service '''
                        os.setuid(user.get_uid())   # Do this first!
                        service_instance = ServiceClass(user)
                        service_instance.init()
                        service_instance.start()
                        return True
                else:
                    print('[NOT ENABLED]')
                    return False
            else:
                print('[NO SUCH USER]')
                return False
        print('[FAILED]')
        return False