1. 程式人生 > 實用技巧 >Python建立Windows服務

Python建立Windows服務

首先讓我們開始安裝Python for Windows擴充套件:

c:test> pip install pywin32

完成後,讓我們編寫該基類,您的Windows服務將是該基類的子類。

'''
SMWinservice
by Davide Mastromatteo

Base class to create winservice in Python
-----------------------------------------

Instructions:

1. Just create a new class that inherits from this base class
2. Define into the new class the variables
   _svc_name_ = "nameOfWinservice"
   _svc_display_name_ = "name of the Winservice that will be displayed in scm"
   _svc_description_ = "description of the Winservice that will be displayed in scm"
3. Override the three main methods:
    def start(self) : if you need to do something at the service initialization.
                      A good idea is to put here the inizialization of the running condition
    def stop(self)  : if you need to do something just before the service is stopped.
                      A good idea is to put here the invalidation of the running condition
    def main(self)  : your actual run loop. Just create a loop based on your running condition
4. Define the entry point of your module calling the method "parse_command_line" of the new class
5. Enjoy
'''

import socket

import win32serviceutil

import servicemanager
import win32event
import win32service


class SMWinservice(win32serviceutil.ServiceFramework):
    '''Base class to create winservice in Python'''

    _svc_name_ = 'pythonService'
    _svc_display_name_ = 'Python Service'
    _svc_description_ = 'Python Service Description'

    @classmethod
    def parse_command_line(cls):
        '''
        ClassMethod to parse the command line
        '''
        win32serviceutil.HandleCommandLine(cls)

    def __init__(self, args):
        '''
        Constructor of the winservice
        '''
        win32serviceutil.ServiceFramework.__init__(self, args)
        self.hWaitStop = win32event.CreateEvent(None, 0, 0, None)
        socket.setdefaulttimeout(60)

    def SvcStop(self):
        '''
        Called when the service is asked to stop
        '''
        self.stop()
        self.ReportServiceStatus(win32service.SERVICE_STOP_PENDING)
        win32event.SetEvent(self.hWaitStop)

    def SvcDoRun(self):
        '''
        Called when the service is asked to start
        '''
        self.start()
        servicemanager.LogMsg(servicemanager.EVENTLOG_INFORMATION_TYPE,
                              servicemanager.PYS_SERVICE_STARTED,
                              (self._svc_name_, ''))
        self.main()

    def start(self):
        '''
        Override to add logic before the start
        eg. running condition
        '''
        pass

    def stop(self):
        '''
        Override to add logic before the stop
        eg. invalidating running condition
        '''
        pass

    def main(self):
        '''
        Main class to be ovverridden to add logic
        '''
        pass

# entry point of the module: copy and paste into the new module
# ensuring you are calling the "parse_command_line" of the new created class
if __name__ == '__main__':
    SMWinservice.parse_command_line()
讓我們檢查一下我們剛剛介紹的課程。

def SvcDoRun(self):請求服務啟動時將呼叫的方法。

def SvcStop(self):請求服務停止時將呼叫的方法。

def start(self):這是一種方法,在服務啟動時(啟動之前),您需要重寫是否需要做某事

def stop(self):服務停止時(停止之前)是否需要執行某些操作,將要求您覆蓋此方法

def main(self):這是將包含指令碼邏輯的方法,通常是在迴圈中使其保持活動狀態直到服務停止。

def parse_command_line(cls):這是處理命令列介面的方法,可用於安裝和更新Windows服務

您能看到使用pywin32與系統互動以建立Windows服務有多麼容易嗎?

最後提到的是以下變數:

svc_name = "PythonCornerExample"
svc_display_name = "Python Corner's Winservice Example"
svc_description = "That's a great winservice! :)"

這只是三個變數,其中包含服務的名稱,“友好名稱”(Windows將使用該名稱在mmc控制檯上顯示名稱)以及服務的簡短說明。

一如既往,足夠多的討論,讓我們編寫一些有用的程式碼!


假設我們要建立一個Winservice,該Winservice在啟動時每5秒在C:驅動器上建立一個隨機檔案。

什麼?你覺得這很蠢嗎?好了,將其安裝在您的老闆PC上,將目標資料夾設定為其使用者的桌面,您將改變主意。:)

但是,如何才能達到這個結果呢?超級容易。

  • 子類化我們剛剛遇到的SMWinservice類。
  • 在新類上,覆蓋三個變數_svc_name__svc_display_name__svc_description_
  • 覆蓋“開始”方法以設定執行條件。設定一個布林變數就足夠了。
  • 當請求停止服務時,重寫“stop”方法以使執行狀況無效。
  • 覆蓋“main”方法以新增每5秒建立一個隨機檔案的邏輯
  • 將呼叫新增到“parse_command_line”函式以處理命令列介面。

結果應該是這樣的:

import time
import random
from pathlib import Path
from SMWinservice import SMWinservice

class PythonCornerExample(SMWinservice):
    _svc_name_ = "PythonCornerExample"
    _svc_display_name_ = "Python Corner's Winservice Example"
    _svc_description_ = "That's a great winservice! :)"

    def start(self):
        self.isrunning = True

    def stop(self):
        self.isrunning = False

    def main(self):
        i = 0
        while self.isrunning:
            random.seed()
            x = random.randint(1, 1000000)
            Path(f'c:{x}.txt').touch()
            time.sleep(5)

if __name__ == '__main__':
    PythonCornerExample.parse_command_line()

而已!現在是時候安裝我們新建立的winservice了。只需開啟命令提示符,導航到指令碼目錄並使用以下命令安裝服務:

C:test> python PythonCornerExample.py install
Installing service PythonCornerExample
Service installed

將來,如果您想更改服務程式碼,只需對其進行修改並使用以下命令重新安裝該服務

C:test> python PythonCornerExample.py update
Changing service configuration
Service updated

現在,開啟“服務” m​​sc管理單元

C:test> mmc Services.msc

找到新的PythonCornerExamplewinservice,然後右鍵單擊並選擇屬性。在這裡,您可以啟動服務並隨意配置。

現在嘗試啟動服務,然後檢視C:資料夾的內容。

您可以看到所有這些檔案都已建立到C:資料夾嗎?是的,這有效!

但是現在是時候停止它了!:)您可以在以前的視窗中執行此操作,也可以僅使用命令列來執行此操作

C:test> net stop PythonCornerExample

Il servizio Python Corner's Winservice Example sta per essere arrestato.. 
Servizio Python Corner's Winservice Example arrestato.

如果出問題了...

用Python編寫Windows服務可能會發生幾個已知的問題。如果您已經成功安裝了該服務但啟動了該服務,則會收到錯誤訊息,請按照以下步驟對服務進行故障排除:

  • 檢查Python是否在您的PATH變數中。它必須在那裡。要檢查這一點,只需開啟命令提示符,然後嘗試通過鍵入“ python”來啟動python直譯器。如果開始,那很好。
  • 確保具有該檔案C:\Program Files\Python36\Lib\site-packages\win32\pywintypes36.dll(請注意,“ 36”是您的Python安裝版本)。如果您沒有此檔案,請從中C:\Program Files\Python36\Lib\site-packages\pywin32_system32\pywintypes36.dll複製並複製到C:\Program Files\Python36\Lib\site-packages\win32

如果仍然有問題,請嘗試以除錯模式執行Python指令碼。要在上一個示例中嘗試此操作,請開啟一個終端,導航到指令碼所在的目錄,然後鍵入

c:test> python PythonCornerExample.py debug

好的,今天就這些,這只是使用Python開發Windows服務的簡短介紹。自己嘗試一下,…快樂編碼!