如何在Windows中将Python脚本作为服务运行?

时间:2008-08-28 14:28:04

标签: python windows cross-platform

我正在描绘一组程序的架构,这些程序共享存储在数据库中的各种相互关联的对象。我希望其中一个程序充当服务,为这些对象的操作提供更高级别的接口,以及其他程序通过该服务访问对象。

我目前的目标是将Python和Django框架作为实现该服务的技术。我很确定我想知道如何在Linux中守护Python程序。但是,它是系统应支持Windows的可选规范项。我对Windows编程没什么经验,也没有使用Windows服务的经验。

是否可以将Python程序作为Windows服务运行(即在没有用户登录的情况下自动运行)?我不一定要实现这部分,但我需要大致了解如何这样做是为了决定是否按照这些方式进行设计。

编辑:感谢目前为止的所有答案,它们非常全面。我想知道一件事: Windows如何了解我的服务?我可以使用本机Windows实用程序进行管理吗? 在/etc/init.d中放置启动/停止脚本等同于什么?

14 个答案:

答案 0 :(得分:236)

是的,你可以。我使用ActivePython附带的pythoncom库来实现,或者可以使用pywin32(Python for Windows扩展)安装。

这是简单服务的基本框架:

import win32serviceutil
import win32service
import win32event
import servicemanager
import socket


class AppServerSvc (win32serviceutil.ServiceFramework):
    _svc_name_ = "TestService"
    _svc_display_name_ = "Test Service"

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

    def SvcStop(self):
        self.ReportServiceStatus(win32service.SERVICE_STOP_PENDING)
        win32event.SetEvent(self.hWaitStop)

    def SvcDoRun(self):
        servicemanager.LogMsg(servicemanager.EVENTLOG_INFORMATION_TYPE,
                              servicemanager.PYS_SERVICE_STARTED,
                              (self._svc_name_,''))
        self.main()

    def main(self):
        pass

if __name__ == '__main__':
    win32serviceutil.HandleCommandLine(AppServerSvc)

您的代码将使用main()方法 - 通常使用某种无限循环,可能会通过检查您在SvcStop方法中设置的标志来中断

答案 1 :(得分:34)

尽管我在几周之后对所选择的答案进行了投票,但与此同时,我在这个主题上更加努力。感觉就像有一个特殊的Python安装和使用特殊模块来运行脚本作为服务是错误的方式。那便携性等等呢?

我偶然发现了精彩的Non-sucking Service Manager,这使得处理Windows服务非常简单明了。我想,既然我可以将选项传递给已安装的服务,我也可以选择我的Python可执行文件并将我的脚本作为选项传递。

我还没有尝试过这个解决方案,但我现在会这样做,并在整个过程中更新这篇文章。我也有兴趣在Windows上使用virtualenvs,所以我迟早会提出一个教程并在这里链接到它。

答案 2 :(得分:24)

有几种方法可以将几乎任何Windows可执行文件安装为服务。

方法1:使用rktools.exe

中的instsrv和srvany

对于Windows Home Server或Windows Server 2003(也适用于WinXP),Windows Server 2003 Resource Kit Tools附带了可与之配合使用的实用程序,称为 instsrv.exe SRVANY.EXE 即可。有关如何使用这些工具的详细信息,请参阅此Microsoft知识库文章KB137890

对于Windows Home Server,这些实用程序有一个很好的用户友好包装,名为aptly“Any Service Installer”。

方法2:使用ServiceInstaller for Windows NT

使用ServiceInstaller for Windows NTdownload-able here)与python instructions available有另一种选择。与名称相反,它也适用于Windows 2000和Windows XP。以下是有关如何将python脚本安装为服务的一些说明。

  

安装Python脚本

     

运行ServiceInstaller以创建新的   服务。 (在这个例子中,它是   假设安装了python   C:\ python25)

Service Name  : PythonTest
Display Name : PythonTest 
Startup : Manual (or whatever you like)
Dependencies : (Leave blank or fill to fit your needs)
Executable : c:\python25\python.exe
Arguments : c:\path_to_your_python_script\test.py
Working Directory : c:\path_to_your_python_script
     

安装后,打开Control   面板的服务小程序,选择和   启动PythonTest服务。

在我的初步回答之后,我注意到已经在SO上发布了密切相关的Q& A.另见:

Can I run a Python script as a service (in Windows)? How?

How do I make Windows aware of a service I have written in Python?

答案 3 :(得分:23)

实现此目的的最简单方法是使用本机命令sc.exe:

dist

<强>参考文献:

  1. https://technet.microsoft.com/en-us/library/cc990289(v=ws.11).aspx
  2. When creating a service with sc.exe how to pass in context parameters?

答案 4 :(得分:19)

最简单的方法是使用: NSSM - 非吸吮服务管理器:

1 - 在https://nssm.cc/download

上下载

2 - 将python程序安装为服务:以管理员身份启用Win

c:&gt; nssm.exe安装WinService

3 - 在NSSM的控制台上:

路径:C:\ Python27 \ Python27.exe

启动目录:C:\ Python27

参数:c:\ WinService.py

4 - 检查services.msc上创建的服务

答案 5 :(得分:12)

逐步解释如何使其发挥作用:

1-首先根据上面提到的基本骨架创建一个python文件。并将其保存到路径中,例如:&#34; c:\ PythonFiles \ AppServerSvc.py&#34;

import win32serviceutil
import win32service
import win32event
import servicemanager
import socket


class AppServerSvc (win32serviceutil.ServiceFramework):
    _svc_name_ = "TestService"
    _svc_display_name_ = "Test Service"


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

    def SvcStop(self):
        self.ReportServiceStatus(win32service.SERVICE_STOP_PENDING)
        win32event.SetEvent(self.hWaitStop)

    def SvcDoRun(self):
        servicemanager.LogMsg(servicemanager.EVENTLOG_INFORMATION_TYPE,
                          servicemanager.PYS_SERVICE_STARTED,
                          (self._svc_name_,''))
        self.main()

    def main(self):
        # Your business logic or call to any class should be here
        # this time it creates a text.txt and writes Test Service in a daily manner 
        f = open('C:\\test.txt', 'a')
        rc = None
        while rc != win32event.WAIT_OBJECT_0:
            f.write('Test Service  \n')
            f.flush()
            # block for 24*60*60 seconds and wait for a stop event
            # it is used for a one-day loop
            rc = win32event.WaitForSingleObject(self.hWaitStop, 24 * 60 * 60 * 1000)
        f.write('shut down \n')
        f.close()

if __name__ == '__main__':
    win32serviceutil.HandleCommandLine(AppServerSvc)

2 - 在此步骤中,我们应该注册我们的服务。

管理员运行命令提示符,然后键入:

  

sc create TestService binpath =&#34; C:\ Python36 \ Python.exe c:\ PythonFiles \ AppServerSvc.py&#34; DisplayName =&#34; TestService&#34; start = auto

binpath 的第一个参数是python.exe的路径

binpath 的第二个参数是我们创建的python文件的路径

不要错过你应该在每个&#34; = &#34;之后放置一个空格。标志。

然后,如果一切正常,你应该看到

  

[SC] CreateService SUCCESS

现在你的python服务现在作为windows服务安装。您可以在Service Manager和注册表中看到它:

HKEY_LOCAL_MACHINE \ SYSTEM \ CURRENTCONTROLSET \服务\ TestService的

3-现在好。您可以在服务管理器上启动服务。

您可以执行提供此服务框架的每个python文件。

答案 6 :(得分:2)

我开始使用pywin32作为服务托管。

一切都很好,但是我遇到了系统启动时服务无法在30秒内启动(Windows的默认超时)的问题。对我来说至关重要,因为Windows启动是在一台物理机上托管的多个虚拟机上同时进行的,并且IO负载很大。 错误消息是:

Error 1053: The service did not respond to the start or control request in a timely fashion.

Error 7009: Timeout (30000 milliseconds) waiting for the <ServiceName> service to connect.

我在pywin上进行了很多工作,但最终按照建议in this answer使用NSSM。迁移到它非常容易。

答案 7 :(得分:1)

使用循环或子线程的完整pywin32示例

反复进行几天后,这是我希望找到的答案,使用pywin32使其保持良好状态并自成一体。

这是一种基于循环和一种基于线程的解决方案的完整工作代码。 尽管我只测试了2.7和Win7的最新版本,但它可能同时在python 2和3上运行。该循环应适合轮询代码,而踏步应该可以处理更多类似服务器的代码。 waitress wsgi服务器似乎没有很好的正常关闭方法,因此似乎可以很好地工作。

我还想指出,似乎有很多示例,例如this,它们几乎是有用的,但实际上却具有误导性,因为它们盲目地剪切和粘贴了其他示例。我可能是错的。但是如果您从不等待,为什么还要创建一个活动?

那表示我仍然觉得我在这里有些动摇,尤其是关于线程版本的退出情况有多干净,但是至少我相信这里没有什么“误导性”。 / p>

要运行,只需将代码复制到文件中,然后按照说明进行操作即可。

更新:

使用一个简单的标志终止线程。重要的一点是要打印“线程完成”。
有关从不合作的服务器线程退出的更详细的示例,请参阅我的post about the waitress wsgi server

# uncomment mainthread() or mainloop() call below
# run without parameters to see HandleCommandLine options
# install service with "install" and remove with "remove"
# run with "debug" to see print statements
# with "start" and "stop" watch for files to appear
# check Windows EventViever for log messages

import socket
import sys
import threading
import time
from random import randint
from os import path

import servicemanager
import win32event
import win32service
import win32serviceutil
# see http://timgolden.me.uk/pywin32-docs/contents.html for details


def dummytask_once(msg='once'):
    fn = path.join(path.dirname(__file__),
                '%s_%s.txt' % (msg, randint(1, 10000)))
    with open(fn, 'w') as fh:
        print(fn)
        fh.write('')


def dummytask_loop():
    global do_run
    while do_run:
        dummytask_once(msg='loop')
        time.sleep(3)


class MyThread(threading.Thread):
    def __init__(self):
        threading.Thread.__init__(self)

    def run(self):
        global do_run
        do_run = True
        print('thread start\n')
        dummytask_loop()
        print('thread done\n')

    def exit(self):
        global do_run
        do_run = False


class SMWinservice(win32serviceutil.ServiceFramework):
    _svc_name_ = 'PyWinSvc'
    _svc_display_name_ = 'Python Windows Service'
    _svc_description_ = 'An example of a windows service in Python'

    @classmethod
    def parse_command_line(cls):
        win32serviceutil.HandleCommandLine(cls)

    def __init__(self, args):
        win32serviceutil.ServiceFramework.__init__(self, args)
        self.stopEvt = win32event.CreateEvent(None, 0, 0, None)  # create generic event
        socket.setdefaulttimeout(60)

    def SvcStop(self):
        servicemanager.LogMsg(servicemanager.EVENTLOG_INFORMATION_TYPE,
                            servicemanager.PYS_SERVICE_STOPPED,
                            (self._svc_name_, ''))
        self.ReportServiceStatus(win32service.SERVICE_STOP_PENDING)
        win32event.SetEvent(self.stopEvt)  # raise event

    def SvcDoRun(self):
        servicemanager.LogMsg(servicemanager.EVENTLOG_INFORMATION_TYPE,
                            servicemanager.PYS_SERVICE_STARTED,
                            (self._svc_name_, ''))
        # UNCOMMENT ONE OF THESE
        # self.mainthread()
        # self.mainloop()

    # Wait for stopEvt indefinitely after starting thread.
    def mainthread(self):
        print('main start')
        self.server = MyThread()
        self.server.start()
        print('wait for win32event')
        win32event.WaitForSingleObject(self.stopEvt, win32event.INFINITE)
        self.server.exit()
        print('wait for thread')
        self.server.join()
        print('main done')

    # Wait for stopEvt event in loop.
    def mainloop(self):
        print('loop start')
        rc = None
        while rc != win32event.WAIT_OBJECT_0:
            dummytask_once()
            rc = win32event.WaitForSingleObject(self.stopEvt, 3000)
        print('loop done')


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

答案 8 :(得分:0)

使用##Importing necessary packages. import numpy as np import nptdms ##Opening TDMS file. file = nptdms.TdmsFile(my_file) ##Gets all file objects (group entities); each 'key/value' pair comprises a path and an object pointing to a group on the file. fileObjs = list(file.objects.items()) ##For each object (group), the written properties are retrieved and listed. The indexing is set to skip the root group. for i in range(1, len(fileObjs)): list(fileObjs[i][1].properties.items()) ############################################################################ ############################################################################ ##Or, using list comprehension: for propValueTuples in [list(fileObj[1].properties.items()) for fileObj in list(file.objects.items())[1::]]: propValueTuples 接受的答案有效,但是很复杂,并且使调试和更改变得更加困难。使用NSSM(the Non-Sucking Service Manager)更容易 。您编写并舒适地调试了一个普通的python程序,当它最终运行时,您可以使用NSSM将其安装为不到一分钟的服务时间:

在提升的(管理员)命令提示符下,运行win32serviceutil并填写以下选项:

  • 路径 :( python.exe的路径,例如nssm.exe install NameOfYourService
  • 参数 :( Python脚本的路径,例如C:\Python27\Python.exe

顺便说一句,如果您的程序打印了您希望保存在日志文件中的有用消息,NSSM也可以处理此问题,并且为您提供更多帮助。

答案 9 :(得分:0)

对于任何想要在VENV或Pycharm中创建服务的人!!!!!!!

在阅读完所有提示并创建了一些脚本之后,如果可以运行python service.py installpython service.py debug,但是python service.py start没有响应。

可能是venv问题引起的,因为Windows服务是由执行程序PROJECT\venv\Lib\site-packages\win32\pythonservice.exe启动您的服务的。

您可以使用powershellcmd来测试服务,以查找更多错误的详细信息。

PS C:\Users\oraant> E:

PS E:\> cd \Software\PythonService\venv\Lib\site-packages\win32

PS E:\Software\PythonService\venv\Lib\site-packages\win32> .\pythonservice.exe -debug ttttt
Debugging service ttttt - press Ctrl+C to stop.
Error 0xC0000004 - Python could not import the service's module

Traceback (most recent call last):
  File "E:\Software\PythonService\my_service.py", line 2, in <module>
    import win32serviceutil
ModuleNotFoundError: No module named 'win32serviceutil'

(null): (null)

如果您遇到类似我的错误,则可以在另一个问题中检查我的答案,我已将其修复并发布了代码here

答案 10 :(得分:0)

在python 3+中启用nssm

(我使用pyinstaller将.py文件转换为.exe)

nssm: 如前所述

  • 运行nssm install {ServiceName}
  • 在NSSM的控制台上:

    路径:到\您的\ program.exe的路径

    启动目录: path \ to \ your \#与路径相同,但没有program.exe

    参数:空

答案 11 :(得分:0)

这个答案是从StackOverflow上的多个来源抄袭的-大多数在上面,但是我忘记了其他-抱歉。它很简单,脚本按“原样”运行。对于发行版,您需要测试脚本,然后将其复制到服务器并停止/启动关联的服务。它应该适用于所有脚本语言(Python,Perl,node.js),以及批处理脚本(如GitBash,PowerShell甚至旧的DOS bat脚本)。 pyGlue是Windows服务和脚本之间的粘合剂。

'''
A script to create a Windows Service, which, when started, will run an executable with the specified parameters.
Optionally, you can also specify a startup directory

To use this script you MUST define (in class Service)
1. A name for your service (short - preferably no spaces)
2. A display name for your service (the name visibile in Windows Services)
3. A description for your service (long details visible when you inspect the service in Windows Services)
4. The full path of the executable (usually C:/Python38/python.exe or C:WINDOWS/System32/WindowsPowerShell/v1.0/powershell.exe
5. The script which Python or PowerShell will run(or specify None if your executable is standalone - in which case you don't need pyGlue)
6. The startup directory (or specify None)
7. Any parameters for your script (or for your executable if you have no script)

NOTE: This does not make a portable script.
The associated '_svc_name.exe' in the dist folder will only work if the executable,
(and any optional startup directory) actually exist in those locations on the target system

Usage: 'pyGlue.exe [options] install|update|remove|start [...]|stop|restart [...]|debug [...]'
Options for 'install' and 'update' commands only:
        --username domain\\username : The Username the service is to run under
        --password password : The password for the username
        --startup [manual|auto|disabled|delayed] : How the service starts, default = manual
        --interactive : Allow the service to interact with the desktop.
        --perfmonini file: .ini file to use for registering performance monitor data
        --perfmondll file: .dll file to use when querying the service for performance data, default = perfmondata.dll
Options for 'start' and 'stop' commands only:
        --wait seconds: Wait for the service to actually start or stop.
                If you specify --wait with the 'stop' option, the service and all dependent services will be stopped,
                each waiting the specified period.
'''

# Import all the modules that make life easy
import servicemanager
import socket
import sys
import win32event
import win32service
import win32serviceutil
import win32evtlogutil
import os
from logging import Formatter, Handler
import logging
import subprocess


# Define the win32api class
class Service (win32serviceutil.ServiceFramework):
        # The following variable are edited by the build.sh script
        _svc_name_ = "TestService"
        _svc_display_name_ = "Test Service"
        _svc_description_ = "Test Running Python Scripts as a Service"
        service_exe = 'c:/Python27/python.exe'
        service_script = None
        service_params = []
        service_startDir = None

        # Initialize the service
        def __init__(self, args):
                win32serviceutil.ServiceFramework.__init__(self, args)
                self.hWaitStop = win32event.CreateEvent(None, 0, 0, None)
                self.configure_logging()
                socket.setdefaulttimeout(60)

        # Configure logging to the WINDOWS Event logs
        def configure_logging(self):
                self.formatter = Formatter('%(message)s')
                self.handler = logHandler()
                self.handler.setFormatter(self.formatter)
                self.logger = logging.getLogger()
                self.logger.addHandler(self.handler)
                self.logger.setLevel(logging.INFO)

        # Stop the service
        def SvcStop(self):
                self.ReportServiceStatus(win32service.SERVICE_STOP_PENDING)
                win32event.SetEvent(self.hWaitStop)

        # Run the service
        def SvcDoRun(self):
                self.main()

        # This is the service
        def main(self):

                # Log that we are starting
                servicemanager.LogMsg(servicemanager.EVENTLOG_INFORMATION_TYPE, servicemanager.PYS_SERVICE_STARTED,
                                                          (self._svc_name_, ''))

                # Fire off the real process that does the real work
                logging.info('%s - about to call Popen() to run %s %s %s', self._svc_name_, self.service_exe, self.service_script, self.service_params)
                self.process = subprocess.Popen([self.service_exe, self.service_script] + self.service_params, shell=False, cwd=self.service_startDir)
                logging.info('%s - started process %d', self._svc_name_, self.process.pid)

                # Wait until WINDOWS kills us - retrigger the wait for stop every 60 seconds
                rc = None
                while rc != win32event.WAIT_OBJECT_0:
                        rc = win32event.WaitForSingleObject(self.hWaitStop, (1 * 60 * 1000))

                # Shut down the real process and exit
                logging.info('%s - is terminating process %d', self._svc_name_, self.process.pid)
                self.process.terminate()
                logging.info('%s - is exiting', self._svc_name_)


class logHandler(Handler):
        '''
Emit a log record to the WINDOWS Event log
        '''

        def emit(self, record):
                servicemanager.LogInfoMsg(record.getMessage())


# The main code
if __name__ == '__main__':
        '''
Create a Windows Service, which, when started, will run an executable with the specified parameters.
        '''

        # Check that configuration contains valid values just in case this service has accidentally
        # been moved to a server where things are in different places
        if not os.path.isfile(Service.service_exe):
                print('Executable file({!s}) does not exist'.format(Service.service_exe), file=sys.stderr)
                sys.exit(0)
        if not os.access(Service.service_exe, os.X_OK):
                print('Executable file({!s}) is not executable'.format(Service.service_exe), file=sys.stderr)
                sys.exit(0)
        # Check that any optional startup directory exists
        if (Service.service_startDir is not None) and (not os.path.isdir(Service.service_startDir)):
                print('Start up directory({!s}) does not exist'.format(Service.service_startDir), file=sys.stderr)
                sys.exit(0)

        if len(sys.argv) == 1:
                servicemanager.Initialize()
                servicemanager.PrepareToHostSingle(Service)
                servicemanager.StartServiceCtrlDispatcher()
        else:
                # install/update/remove/start/stop/restart or debug the service
                # One of those command line options must be specified
                win32serviceutil.HandleCommandLine(Service)

现在需要一些编辑,您不希望所有服务都称为“ pyGlue”。因此,有一个脚本(build.sh)可以插入这些位并创建自定义的“ pyGlue”并创建“ .exe”。这是作为Windows服务安装的“ .exe”。安装后,您可以将其设置为自动运行。

#!/bin/sh
# This script build a Windows Service that will install/start/stop/remove a service that runs a script
# That is, executes Python to run a Python script, or PowerShell to run a PowerShell script, etc

if [ $# -lt 6 ]; then
        echo "Usage: build.sh Name Display Description Executable Script StartupDir [Params]..."
        exit 0
fi

name=$1
display=$2
desc=$3
exe=$4
script=$5
startDir=$6
shift; shift; shift; shift; shift; shift
params=
while [ $# -gt 0 ]; do
        if [ "${params}" != "" ]; then
                params="${params}, "
        fi
        params="${params}'$1'"
        shift
done

cat pyGlue.py | sed -e "s/pyGlue/${name}/g" | \
        sed -e "/_svc_name_ =/s?=.*?= '${name}'?" | \
        sed -e "/_svc_display_name_ =/s?=.*?= '${display}'?" | \
        sed -e "/_svc_description_ =/s?=.*?= '${desc}'?" | \
        sed -e "/service_exe =/s?=.*?= '$exe'?" | \
        sed -e "/service_script =/s?=.*?= '$script'?" | \
        sed -e "/service_params =/s?=.*?= [${params}]?" | \
        sed -e "/service_startDir =/s?=.*?= '${startDir}'?" > ${name}.py

cxfreeze ${name}.py --include-modules=win32timezone

安装-将“ .exe”服务器和脚本复制到指定的文件夹。使用“安装”选项,以管理员身份运行“ .exe”。以Adminstrator的身份打开Windows Services,然后开始服务。要进行升级,只需复制脚本的新版本并停止/启动服务即可。

现在每个服务器都是不同的-不同的Python安装,不同的文件夹结构。我为每个服务器维护一个文件夹,其中包含pyGlue.py和build.sh的副本。然后,我创建了一个“ serverBuild.sh”脚本,用于在该服务器上重建所有服务。

# A script to build all the script based Services on this PC
sh build.sh AutoCode 'AutoCode Medical Documents' 'Autocode Medical Documents to SNOMED_CT and AIHW codes' C:/Python38/python.exe autocode.py C:/Users/russell/Documents/autocoding -S -T

答案 12 :(得分:-1)

https://www.chrisumbel.com/article/windows_services_in_python

  1. 关注PySvc.py

  2. 更改dll文件夹

我知道这很老了,但是我永远都被这个问题困扰了。对我来说,通过复制此文件pywintypes36.dll

可以解决此特定问题。

从-> Python36 \ Lib \ site-packages \ pywin32_system32

至-> Python36 \ Lib \ site-packages \ win32

setx /M PATH "%PATH%;C:\Users\user\AppData\Local\Programs\Python\Python38-32;C:\Users\user\AppData\Local\Programs\Python\Python38-32\Scripts;C:\Users\user\AppData\Local\Programs\Python\Python38-32\Lib\site-packages\pywin32_system32;C:\Users\user\AppData\Local\Programs\Python\Python38-32\Lib\site-packages\win32
  1. 通过以下方式更改python文件夹的路径

cd C:\Users\user\AppData\Local\Programs\Python\Python38-32

  1. NET START PySvc
  2. NET STOP PySvc

答案 13 :(得分:-2)

pysc:Service Control Manager on Python

作为服务taken from pythonhosted.org运行的示例脚本:

from xmlrpc.server import SimpleXMLRPCServer

from pysc import event_stop


class TestServer:

    def echo(self, msg):
        return msg


if __name__ == '__main__':
    server = SimpleXMLRPCServer(('127.0.0.1', 9001))

    @event_stop
    def stop():
        server.server_close()

    server.register_instance(TestServer())
    server.serve_forever()
     

创建并启动服务

import os
import sys
from xmlrpc.client import ServerProxy

import pysc


if __name__ == '__main__':
    service_name = 'test_xmlrpc_server'
    script_path = os.path.join(
        os.path.dirname(__file__), 'xmlrpc_server.py'
    )
    pysc.create(
        service_name=service_name,
        cmd=[sys.executable, script_path]
    )
    pysc.start(service_name)

    client = ServerProxy('http://127.0.0.1:9001')
    print(client.echo('test scm'))
     

停止并删除服务

import pysc

service_name = 'test_xmlrpc_server'

pysc.stop(service_name)
pysc.delete(service_name)
pip install pysc