python 做服务程序_windows平台把python程序制作成windows服务并开机启动(实践的坑)...

本文档介绍了如何将Python程序在Windows平台上转化为服务,并实现开机启动。通过编写特定的服务框架代码,结合PyInstaller和sc命令,将Python应用打包为Windows服务。在过程中可能会遇到信号错误和静态文件未打包的问题,文中详细阐述了解决方案。
摘要由CSDN通过智能技术生成

简介

通常在windows平台上开发完python服务后,需要通过引用虚拟环境后再运行,或者使用IDE软件启动,但如果想做成开机启动的本地服务,每次都这样启动就太麻烦了。

该文档介绍这个方法是把python程序制作成一个windows,启停特别方便,而且还可以设置开机启动。虚拟环境依赖的库也不需要考虑,只要在构建的时候在虚拟环境下构建,就会自动将依赖的库打包进去。

1、首先,有一段大家通用的代码,可以将python程序制作成服务。直接拷贝使用即可,在SvcDoRun函数内写上拉起自己服务的代码。

# -*- coding:utf-8 -*-

import win32serviceutil

import win32service

import win32event

import sys

import os

#设置编码

reload(sys)

sys.setdefaultencoding('utf-8')

#windows服务中显示的名字

class zlsService(win32serviceutil.ServiceFramework):

_svc_name_ ='web_movie' ###可以根据自己喜好修改

_svc_display_name_ ='web_movie'  ###可以根据自己喜好修改

_svc_description_ ='web_movie'  ###可以根据自己喜好修改

def __init__(self,args):

win32serviceutil.ServiceFramework.__init__(self,args)

self.stop_event = win32event.CreateEvent(None,0,0,None)

self.run =True

def SvcDoRun(self):

# 这里是你的启动代码,由于我的是flask框架程序,只需要把我的主文件from过来即可。

from web_movieimport app

app.run()

def SvcStop(self):

self.ReportServiceStatus(win32service.SERVICE_STOP_PENDING)

win32event.SetEvent(self.stop_event)

self.ReportServiceStatus(win32service.SERVICE_STOPPED)

self.run =False

if __name__ =='__main__':

import sys

import servicemanager

if len(sys.argv) ==1:

try:

evtsrc_dll = os.path.abspath(servicemanager.__file__)

servicemanager.PrepareToHostSingle(zlsService)#如果修改过名字,名字要统一

servicemanager.Initialize('zlsService',evtsrc_dll)#如果修改过名字,名字要统一

servicemanager.StartServiceCtrlDispatcher()

except win32service.erroras details:

import winerror

if details == winerror.ERROR_FAILED_SERVICE_CONTROLLER_CONNECT:

win32serviceutil.usage()

else:

win32serviceutil.HandleCommandLine(zlsService)#如果修改过名字,名字要统一

2、安装构建环境需要用的库,在虚拟环境内安装即可。

pip install PyInstaller==3.4

pip install pywin32==224

3、编写构建bat,其实就几个cmd命令,但是为了方便调试,我还是写成了一个脚本。

:: 停止运行的服务

sc stop web_movie

:: 删除这个服务

sc delete web_movie

:: 等个几秒钟,服务刚停止,文件不会马上释放,不然文件不让删除

TIMEOUT /T 3

:: 删除旧版本构建的内容

rmdir /s/q dist

rmdir /s/q build

del PythonService.spec

:: 构建现在的程序,这里有个坑,由于templates目录和static目录和代码不是直接引用,在pyinstaller构建的时候会忽略,导致服务无法运行,后面详细介绍。

pyinstaller -F --add-data "templates;templates" --add-data "static;static" PythonService.py

:: 将构建好的exe程序安装到系统服务

dist\PythonService.exe install

:: 启动服务

sc start web_movie

4、这时候在任务管理器里面就可以看到已经运行的服务了

5、如果不能启动,排查方法

如果启动后立即停止,或者弹窗说“服务没有及时响应启动或控制请求”,这时候可以查看windows的计算机管理界面应用日志,来看详细信息。

6、我遇到的坑

Traceback (most recent call last):

File "site-packages\win32\lib\win32serviceutil.py", line 839, in SvcRun

File "PythonService.py", line 28, in SvcDoRun

File "site-packages\flask\app.py", line 943, in run

File "site-packages\werkzeug\serving.py", line 812, in run_simple

File "site-packages\werkzeug\_reloader.py", line 267, in run_with_reloader

ValueError: signal only works in main thread

上面这个报错使我的代码出现过得,经过我的各种最小化测试,发现这个错误是加载配置项的时候就会出现,最终定位到了我的一行配置文件。

DEBUG =True,这一行配置让我排查了整整一天。

7、我遇到的坑

修复了上面的问题,我的的服务终于起来了,但是又发现,在浏览器里面竟然无法访问。如下提示:

Internal Server Error

The server encountered an internal error and was unable to complete your request. Either the server is overloaded or there is an error in the application.

这个问题也让我苦恼了很久,在我最小化测试的时候,缩减到仅剩一个hello world都无法正常显示,但是创建一个新的flask项目就可以正常显示,经过我细心的diff这两个项目,

发现我在return的时候使用了render_template模板,然而这个目录在pyinstaller的时候,并没有打包进来,然后这一切都明白了,就是因为在构建的时候没有将这个目录添加进来,

导致项目启动后无法使用模板文件。

修复方法就是bat文件内写的,添加上静态目录的编译就可以了。

pyinstaller -F --add-data "templates;templates" --add-data "static;static" PythonService.py

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 可以使用 Python 模块 `win32service` 和 `win32serviceutil` 来写一个 Windows 服务,实现持续检测 `a.exe` 程序是否启动。 下面是一个简单的示例代码: ``` import win32service import win32serviceutil import win32event import win32process import time class MyService(win32serviceutil.ServiceFramework): _svc_name_ = "MyService" _svc_display_name_ = "My Service" def __init__(self, args): win32serviceutil.ServiceFramework.__init__(self, args) self.hWaitStop = win32event.CreateEvent(None, 0, 0, None) def SvcStop(self): self.ReportServiceStatus(win32service.SERVICE_STOP_PENDING) win32event.SetEvent(self.hWaitStop) def SvcDoRun(self): while True: # 检测 a.exe 程序是否启动 try: pid = win32process.FindProcessesByName("a.exe")[0] print("a.exe启动") except: print("a.exe 没有启动") # 每隔 5 秒检测一次 time.sleep(5) if __name__ == '__main__': win32serviceutil.HandleCommandLine(MyService) ``` 使用 `python your_script.py install` 安装服务,使用 `python your_script.py start` 启动服务,使用 `python your_script.py stop` 停止服务。 该示例代码会每隔 5 秒检测一次 `a.exe` 程序是否启动,如果启动了,会打印 "a.exe启动",如果没有启动,会打印 "a.exe 没有启动"。 ### 回答2: 要使用Python写一个Windows服务来实现持续检测a.exe程序有没有启动,我们可以使用`pywin32`库来操作Windows API。下面是一个简单示例: ```python import win32serviceutil import win32service import win32event import servicemanager import socket import os # 服务名称 service_name = 'AService' class AService(win32serviceutil.ServiceFramework): _svc_name_ = service_name _svc_display_name_ = service_name def __init__(self, args): win32serviceutil.ServiceFramework.__init__(self, args) self.is_running = False def SvcStop(self): self.ReportServiceStatus(win32service.SERVICE_STOP_PENDING) self.is_running = False def SvcDoRun(self): servicemanager.LogMsg(servicemanager.EVENTLOG_INFORMATION_TYPE, servicemanager.PYS_SERVICE_STARTED, (self._svc_name_, '')) self.is_running = True while self.is_running: # 检测a.exe是否正在运行 if not self.is_a_running(): # 当a.exe没有运行时,在这里执行相应的操作,比如重启a.exe self.start_a() # 检测间隔为5秒 win32event.WaitForSingleObject(self.hWaitStop, 5000) servicemanager.LogMsg(servicemanager.EVENTLOG_INFORMATION_TYPE, servicemanager.PYS_SERVICE_STOPPED, (self._svc_name_, '')) def is_a_running(self): # 获取当前系统中运行的进程列表 pids = os.popen('tasklist /FI "IMAGENAME eq a.exe" /NH').read() return "a.exe" in pids def start_a(self): # 启动a.exe os.startfile('a.exe') if __name__ == '__main__': win32serviceutil.HandleCommandLine(AService) ``` 上述代码创建了一个名为`AService`的Windows服务类,实现持续检测`a.exe`程序有没有启动的功能。在`SvcDoRun`方法中,使用`is_a_running`方法检测`a.exe`进程是否正在运行,如果不在运行则启动`a.exe`。这里以重启`a.exe`为例,你可以根据实际需求,在相应处执行适当的操作。 你可以使用`pyinstaller`将上述代码打包可执行的`.exe`文件,并使用`sc create`命令将其安装为Windows服务,然后使用`net start`命令启动服务。 ### 回答3: 要使用Python编写一个Windows服务来实现持续检测a.exe程序是否启动,可以使用win32service和win32serviceutil模块来实现。 首先,需要安装pywin32库,可以使用以下命令来安装: ``` pip install pypiwin32 ``` 然后,创建一个名为"service.py"的Python脚本,代码如下: ```python import win32serviceutil import win32service import win32event import servicemanager import socket import subprocess class MyService(win32serviceutil.ServiceFramework): _svc_name_ = 'MyService' _svc_display_name_ = 'My 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): while True: try: subprocess.check_output(['tasklist', '/FI', 'IMAGENAME eq a.exe']) except subprocess.CalledProcessError as e: # a.exe is not running pass else: # a.exe is running pass # Wait for 5 seconds before checking again win32event.WaitForSingleObject(self.hWaitStop, 5000) if __name__ == '__main__': win32serviceutil.HandleCommandLine(MyService) ``` 此代码定义了一个名为"MyService"的Windows服务类,它继承自win32serviceutil.ServiceFramework。你可以根据实际需要更改服务名称和显示名称。 在主循环(main())中,使用subprocess模块调用tasklist命令来检测a.exe程序是否正在运行。如果找不到a.exe进程,则说明a.exe没有启动。 最后,在命令提示符中以管理员身份运行以下命令来安装该服务: ``` python service.py install ``` 然后,可以使用以下命令来启动服务: ``` python service.py start ``` 这个服务将在后台持续检测a.exe程序有没有启动。如果要停止服务,可以使用以下命令: ``` python service.py stop ``` 希望对你有所帮助!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值