2014-09-10 223 views
15

我已經在python中編寫了Windows服務。如果我從命令提示符運行我的腳本Python Windows服務pyinstaller可執行文件錯誤1053

python runService.py 

當我這樣做時,服務將安裝並正確啓動。我一直在嘗試使用pyinstaller創建一個可執行文件,因爲我已經看到了與py2exe相同的問題。當我運行的服務安裝,但沒有啓動的.exe和我收到以下錯誤

error 1053 the service did not respond to the start or control request in a timely fashion 

我見過很多人都有過這樣的問題,但我似乎無法找到一個明確的答案,如何解決這個問題。

winservice.py

from os.path import splitext, abspath 
from sys import modules, executable 
from time import * 
import win32serviceutil 
import win32service 
import win32event 
import win32api 

class Service(win32serviceutil.ServiceFramework): 
    _svc_name_ = '_unNamed' 
    _svc_display_name_ = '_Service Template' 
    _svc_description_ = '_Description template' 
    def __init__(self, *args): 
     win32serviceutil.ServiceFramework.__init__(self, *args) 
     self.log('init') 
     self.stop_event = win32event.CreateEvent(None, 0, 0, None) 

    #logs into the system event log 
def log(self, msg): 
    import servicemanager 
    servicemanager.LogInfoMsg(str(msg)) 

def sleep(self, minute): 
     win32api.Sleep((minute*1000), True) 
def SvcDoRun(self): 
    self.ReportServiceStatus(win32service.SERVICE_START_PENDING) 
    try: 
     self.ReportServiceStatus(win32service.SERVICE_RUNNING) 
     self.log('start') 
     self.start() 
     self.log('wait') 
     win32event.WaitForSingleObject(self.stop_event, win32event.INFINITE) 
     self.log('done') 
    except Exception, x: 
     self.log('Exception : %s' % x) 
     self.SvcStop() 
def SvcStop(self): 
    self.ReportServiceStatus(win32service.SERVICE_STOP_PENDING) 
    #self.log('stopping') 
    self.stop() 
    #self.log('stopped') 
    win32event.SetEvent(self.stop_event) 
    self.ReportServiceStatus(win32service.SERVICE_STOPPED) 
# to be overridden 
def start(self): pass 
# to be overridden 
def stop(self): pass 

def instart(cls, name, description, display_name=None, stay_alive=True): 
    ''' Install and Start (auto) a Service 

     cls : the class (derived from Service) that implement the Service 
     name : Service name 
     display_name : the name displayed in the service manager 
     decription: the description 
     stay_alive : Service will stop on logout if False 
    ''' 
    cls._svc_name_ = name 
    cls._svc_display_name_ = display_name or name 
    cls._svc_desciption_ = description 
    try: 
     module_path=modules[cls.__module__].__file__ 
    except AttributeError: 

     module_path=executable 
    module_file = splitext(abspath(module_path))[0] 
    cls._svc_reg_class_ = '%s.%s' % (module_file, cls.__name__) 
    if stay_alive: win32api.SetConsoleCtrlHandler(lambda x: True, True) 
    try: 
     win32serviceutil.InstallService(
      cls._svc_reg_class_, 
      cls._svc_name_, 
      cls._svc_display_name_, 
      startType = win32service.SERVICE_AUTO_START, 
      description = cls._svc_desciption_ 
     ) 
     print 'Install ok' 
     win32serviceutil.StartService(
     cls._svc_name_ 
    ) 
    print 'Start ok' 
except Exception, x: 
    print str(x) 

UPDATE

我使用py2exe解決了這個問題,但同樣的變化可能對pyinstaller工作了。我沒有時間自己檢查一下。

我不得不刪除instart函數。以下是我的winservice.py現在讀取。

winservice_py2exe.py

from os.path import splitext, abspath 
from sys import modules, executable 
from time import * 
import win32serviceutil 
import win32service 
import win32event 
import win32api 

class Service(win32serviceutil.ServiceFramework): 
    _svc_name_ = 'actualServiceName' #here is now the name you would input as an arg for instart 
    _svc_display_name_ = 'actualDisplayName' #arg for instart 
    _svc_description_ = 'actualDescription'# arg from instart 
    def __init__(self, *args): 
     win32serviceutil.ServiceFramework.__init__(self, *args) 
     self.log('init') 
     self.stop_event = win32event.CreateEvent(None, 0, 0, None) 

    #logs into the system event log 
def log(self, msg): 
    import servicemanager 
    servicemanager.LogInfoMsg(str(msg)) 

def sleep(self, minute): 
     win32api.Sleep((minute*1000), True) 
def SvcDoRun(self): 
    self.ReportServiceStatus(win32service.SERVICE_START_PENDING) 
    try: 
     self.ReportServiceStatus(win32service.SERVICE_RUNNING) 
     self.log('start') 
     self.start() 
     self.log('wait') 
     win32event.WaitForSingleObject(self.stop_event, win32event.INFINITE) 
     self.log('done') 
    except Exception, x: 
     self.log('Exception : %s' % x) 
     self.SvcStop() 
def SvcStop(self): 
    self.ReportServiceStatus(win32service.SERVICE_STOP_PENDING) 
    #self.log('stopping') 
    self.stop() 
    #self.log('stopped') 
    win32event.SetEvent(self.stop_event) 
    self.ReportServiceStatus(win32service.SERVICE_STOPPED) 
# to be overridden 
def start(self): pass 
# to be overridden 
def stop(self): pass 

if __name__ == '__main__': 
    # Note that this code will not be run in the 'frozen' exe-file!!! 
    win32serviceutil.HandleCommandLine(VidiagService) #added from example included with py2exe 

下面是setup.py文件我py2exe使用。這是從包括在py2exe安裝例如採取:

setup.py

from distutils.core import setup 
import py2exe 
import sys 
if len(sys.argv) == 1: 
    sys.argv.append("py2exe") 
    sys.argv.append("-q") 

class Target: 
    def __init__(self, **kw): 
    self.__dict__.update(kw) 
    # for the versioninfo resources 
    self.version = "0.5.0" 
    self.company_name = "No Company" 
    self.copyright = "no copyright" 
    self.name = "py2exe sample files" 

myservice = Target(
    # used for the versioninfo resource 
    description = "A sample Windows NT service", 
    # what to build. For a service, the module name (not the 
    # filename) must be specified! 
    modules = ["winservice_py2exe"] 
    ) 

setup(
    options = {"py2exe": {"typelibs": 
         # typelib for WMI 
         [('{565783C6-CB41-11D1-8B02-00600806D9B6}', 0, 1, 2)], 
         # create a compressed zip archive 
         "compressed": 1, 
         "optimize": 2}}, 
    # The lib directory contains everything except the executables and the python dll. 
    # Can include a subdirectory name. 
    zipfile = "lib/shared.zip", 

    service = [myservice] 
    ) 

一旦你創建exe文件,你可以使用下面的命令

winservice_py2exe.exe -install 
安裝從命令的服務

然後啓動您可以使用的服務:

net start aTest 

或來自windows服務管理器。所有其他Windows命令行功能現在可以在服務以及Windows服務管理器上運行。

回答

19

嘗試將最後幾行

if __name__ == '__main__': 
    if len(sys.argv) == 1: 
     servicemanager.Initialize() 
     servicemanager.PrepareToHostSingle(Service) 
     servicemanager.StartServiceCtrlDispatcher() 
    else: 
     win32serviceutil.HandleCommandLine(Service) 
+1

這對我使用pyinstaller工作。但是,爲什麼它沒有工作,如果當安裝爲python文件? – enthus1ast 2014-10-27 16:36:19

+0

因爲PythonService.exe會照顧到這一點。 – MrTorture 2014-10-28 17:28:14

+2

OP你應該接受這個答案 – arminb 2015-01-27 12:56:21

2

MrTorture有鑰匙到這個答案,但我想在這裏建立在那。需要注意的是,即使使用win32serviceutil函數以編程方式管理服務(與通過命令提示符安裝,啓動等),您必須包含入口點命令行調度才能在獨立上下文中工作(即當使用pyinstaller或py2exe構建一個exe文件時)。如果你不這樣做,Windows將無法啓動服務。你會得到可怕的1053錯誤!

除此之外,請注意,如果您將服務創建爲較大項目的一部分,則需要構建專用於此服務的exe。你不能把它作爲一個更大的exe文件中的子組件來運行(至少我沒有嘗試過!)。我已經包含了我的安裝功能來證明這一點。

再次,當使用.py腳本,通過pythonservice.exe進行管理時,這些問題都不存在,這些僅僅是獨立exes的問題。

這裏是我的功能代碼的某些不完全片段,但他們可能會爲您節省了不少麻煩:

SUCCESS = winerror.ERROR_SUCCESS 
FAILURE = -1 

class WinServiceManager(): 

    # pass the class, not an instance of it! 
    def __init__(self, serviceClass, serviceExeName=None): 
     self.serviceClass_ = serviceClass 
     # Added for pyInstaller v3 
     self.serviceExeName_ = serviceExeName 

    def isStandAloneContext(self) : 
     # Changed for pyInstaller v3 
     #return sys.argv[0].endswith(".exe") 
     return not(sys.argv[0].endswith(".py")) 

    def dispatch(self): 
     if self.isStandAloneContext() : 
      servicemanager.Initialize() 
      servicemanager.PrepareToHostSingle(self.serviceClass_) 
      servicemanager.Initialize(self.serviceClass_._svc_name_, 
       os.path.abspath(servicemanager.__file__)) 
      servicemanager.StartServiceCtrlDispatcher()   
     else : 
      win32api.SetConsoleCtrlHandler(lambda x: True, True) 
      win32serviceutil.HandleCommandLine(self.serviceClass_)   

    # Service management functions 
    #    
    # Note: all of these functions return: 
    # SUCCESS when explicitly successful 
    # FAILURE when explicitly not successful at their specific purpose 
    # winerror.XXXXXX when win32service (or related class) 
    # throws an error of that nature 
    #------------------------------------------------------------------------ 

    # Note: an "auto start" service is not auto started upon installation! 
    # To install and start simultaneously, use start(autoInstall=True). 
    # That performs both actions for manual start services as well. 
    def install(self): 
     win32api.SetConsoleCtrlHandler(lambda x: True, True)   
     result = self.verifyInstall() 
     if result == SUCCESS or result != FAILURE: return result 
     thisExePath = os.path.realpath(sys.argv[0]) 
     thisExeDir = os.path.dirname(thisExePath)   
     # Changed for pyInstaller v3 - which now incorrectly reports the calling exe 
     # as the serviceModPath (v2 worked correctly!) 
     if self.isStandAloneContext() : 
      serviceModPath = self.serviceExeName_ 
     else : 
      serviceModPath = sys.modules[ self.serviceClass_.__module__ ].__file__   
     serviceModPath = os.path.splitext(os.path.abspath(serviceModPath))[0] 
     serviceClassPath = "%s.%s" % (serviceModPath, self.serviceClass_.__name__) 
     self.serviceClass_._svc_reg_class_ = serviceClassPath 
     # Note: in a "stand alone context", a dedicated service exe is expected 
     # within this directory (important for cases where a separate master exe 
     # is managing services). 
     serviceExePath = (serviceModPath + ".exe") if self.isStandAloneContext() else None   
     isAutoStart = self.serviceClass_._svc_is_auto_start_ 
     startOpt = (win32service.SERVICE_AUTO_START if isAutoStart else 
        win32service.SERVICE_DEMAND_START)   
     try :  
      win32serviceutil.InstallService(
       pythonClassString = self.serviceClass_._svc_reg_class_, 
       serviceName  = self.serviceClass_._svc_name_, 
       displayName  = self.serviceClass_._svc_display_name_, 
       description  = self.serviceClass_._svc_description_, 
       exeName   = serviceExePath, 
       startType   = startOpt 
      ) 
     except win32service.error as e: return e[0] 
     except Exception as e: raise e   
     win32serviceutil.SetServiceCustomOption( 
      self.serviceClass_._svc_name_, WORKING_DIR_OPT_NAME, thisExeDir) 
     for i in range(0, MAX_STATUS_CHANGE_CHECKS) : 
      result = self.verifyInstall() 
      if result == SUCCESS: return SUCCESS 
      time.sleep(STATUS_CHANGE_CHECK_DELAY)    
     return result   

在定義你的業務(從win32serviceutil.ServiceFramework衍生)模塊,包括在這結束它:

if __name__ == "__main__": 
    WinServiceManager(MyServiceClass, "MyServiceBinary.exe").dispatch() 
+0

您有可能分享完整的代碼清單嗎? – mafrosis 2017-09-28 12:15:04

+0

很難確切知道從哪裏開始和結束這件事。我想給出的代碼的數量是有限制的。請告訴我你掛斷了哪些特定部分,我會一起幫你。 – BuvinJ 2017-09-28 12:35:56

+0

注意:我發佈了一些我已經包含的代碼,它可以處理pyInstaller v3的調整。 – BuvinJ 2017-09-28 12:45:26

相關問題