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

How do you run a Python script as a service in Windows?

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

我目前的目标是将python和django框架作为实现该服务的技术。我很确定我知道如何在Linux中监控python程序。但是,它是系统应该支持Windows的可选规范项。我在Windows编程方面经验不足,在Windows服务方面完全没有经验。

是否可以将python程序作为Windows服务运行(即不需要用户登录就自动运行)?我不一定要实现这一部分,但我需要一个大致的概念,如何才能决定是否要沿着这些路线进行设计。

编辑:感谢所有的答案,目前为止,他们是相当全面的。我还想知道一件事:Windows如何知道我的服务?我可以用本机的Windows实用程序管理它吗?在/etc/init.d中放置启动/停止脚本的等效方法是什么?


是的,你可以。我使用ActivePython附带的pythoncom库,或者可以与pywin32(用于Windows扩展的python)一起安装。

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
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方法中设置的标志而中断。


虽然几周前我对选择的答案投了反对票,但与此同时,我在这个话题上挣扎得更厉害。感觉像是有一个特殊的python安装,使用特殊的模块将脚本作为服务运行,这是完全错误的方法。可移植性之类的呢?

我偶然发现了一个非常棒的非吸吮服务管理器,它使处理Windows服务变得非常简单和明智。我想,既然我可以将选项传递给已安装的服务,我也可以选择我的python可执行文件并将脚本作为选项传递。

我还没有尝试过这个解决方案,但是我现在就这样做,并在这个过程中更新这个帖子。我对在Windows上使用virtualenv也很感兴趣,所以我可能迟早会想出一个教程,并链接到这里。


实现这一点的最简单方法是使用本机命令sc.exe:

1
sc create PythonApp binPath="C:\Python34\Python.exe --C:\tmp\pythonscript.py"

参考文献:

  • https://technet.microsoft.com/en-us/library/cc990289(v=ws.11).aspx
  • 使用sc.exe创建服务时,如何传入上下文参数?

  • 实际上,有两种方法可以作为服务安装任何Windows可执行文件。

    方法1:使用RKTools.exe中的instsrv和srvany

    对于Windows Home Server或Windows Server 2003(也可与WinXP一起使用),Windows Server 2003资源工具包工具附带可用于此目的的实用程序,称为instsrv.exe和srvany.exe。有关如何使用这些实用程序的详细信息,请参阅此Microsoft知识库文章KB137890。

    对于Windows Home Server,这些实用程序有一个很好的用户友好包装器,名为"任何服务安装程序"。

    方法2:对Windows NT使用ServiceInstaller

    另一种选择是使用ServiceInstaller for Windows NT(可在此处下载),并提供python指令。与名称相反,它也适用于Windows 2000和Windows XP。下面是一些关于如何将Python脚本安装为服务的说明。

    Installing a Python script

    Run ServiceInstaller to create a new
    service. (In this example, it is
    assumed that python is installed at
    c:\python25)

    1
    2
    3
    4
    5
    6
    7
    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

    After installing, open the Control
    Panel's Services applet, select and
    start the PythonTest service.

    在我最初的回答之后,我注意到已经发布了一些与此密切相关的问题。另请参见:

    我可以(在Windows中)运行python脚本作为服务吗?怎么用?

    如何让Windows知道我用python编写的服务?


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

    1-在https://nssm.cc/download上进行下载

    2-将python程序作为服务安装:win prompt作为admin

    C:>nssm.exe安装WinService

    3-在NSSM控制台上:

    路径:C:python27python27.exe

    启动目录:C:python27

    参数:c:winservice.py

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


    逐步说明如何使其工作:

    1-首先根据上面提到的基本框架创建一个python文件。并将其保存到路径,例如:"c:pythonfilesappserversvc.py"

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    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  
    '
    )
                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
    '
    )
            f.close()

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

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

    以管理员身份运行命令提示并键入:

    sc create TestService binpath="C:\Python36\Python.exe c:\PythonFiles\AppServerSvc.py" DisplayName="TestService" start= auto

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

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

    不要错过,你应该在每个"="符号后放一个空格。

    如果一切正常,你应该看看

    [SC] CreateService SUCCESS

    现在您的python服务安装为windows服务。您可以在服务管理器和注册表中的以下位置看到它:

    HKEY U本地机器系统当前控制集服务测试服务

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

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


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

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

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

    江户十一〔一〕号

    我和Pywin打了很多仗,但最终还是使用了NSSM,正如在这个答案中提出的那样。迁移到那里很容易。


    在python 3中打开nssm+

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

    NSSM:如前所述

    • 运行nssm install servicename
    • 在NSSM控制台上:

      路径:path to your program.exe

      启动目录:路径到您的与路径相同,但没有您的program.exe

      参数:空


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

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

    可能是因为venv问题,因为Windows服务是由exec PROJECT\venv\Lib\site-packages\win32\pythonservice.exe启动的。

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

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    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)

    如果你遇到像我这样的错误,你可以在另一个问题中检查我的答案,我修正了它并把我的代码贴在这里。


    使用win32serviceutil的公认答案是有效的,但是很复杂,调试和更改也很困难。使用NSSM(非吸盘服务管理器)要容易得多。您可以编写并轻松调试普通的python程序,当它最终工作时,您可以使用nssm在不到一分钟的时间内将其作为服务安装:

    从提升的(管理)命令提示符运行nssm.exe install NameOfYourService并填写以下选项:

    • 路径:(python.exe的路径,如C:\Python27\Python.exe)
    • 参数:(python脚本的路径,例如c:\path\to\program.py)

    顺便说一句,如果您的程序打印出您想要保存在日志文件中的有用消息,那么NSSM还可以为您处理这一点以及更多信息。


    pysc:python上的服务控制管理器

    从pythonhosted.org获取的要作为服务运行的示例脚本:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    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()

    Create and start service

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    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'))

    Stop and delete service

    1
    2
    3
    4
    5
    6
    import pysc

    service_name = 'test_xmlrpc_server'

    pysc.stop(service_name)
    pysc.delete(service_name)

    1
    pip install pysc