目录
1.flask程序
编写flask程序,保存为app.py
from flask import Flask, render_template
app = Flask(__name__)
@app.route('/')
def hello_world(): # put application's code here
user = User(username='名字', email='xxxx@qq.com')
person = {
'username': '张三',
'email': 'zhangsan@qq.com'
}
return render_template("index.html", user=user, person=person)
2.引入tornado模块
将app模块一并传入,存储为Service.py
# -*- coding:utf-8 -*-
import asyncio
import inspect
import logging
import os
import socket
import sys
import time
import servicemanager
import win32event
import win32service
import win32serviceutil
import winerror
from tornado.httpserver import HTTPServer
from tornado.ioloop import IOLoop
from tornado.wsgi import WSGIContainer
from app import app
class PythonService(win32serviceutil.ServiceFramework):
_svc_name_ = 'Flask_Web' # 属性中的服务名
_svc_display_name_ = 'FLASK_WEB' # 服务在windows系统中显示的名称
_svc_description_ = 'Python的Flask程序,用于验证设置Windows服务,且开机自启' # 服务的描述
def __init__(self, args):
"""
init的内容可以参考以下网址:
https://www.programcreek.com/python/example/99659/win32serviceutil.ServiceFramework
:param args:
"""
win32serviceutil.ServiceFramework.__init__(self, args)
self.stop_event = win32event.CreateEvent(None, 0, 0, None)
socket.setdefaulttimeout(60) # 套接字设置默认超时时间
self.logger = self._getLogger() # 获取日志对象
self.isAlive = True
def _getLogger(self):
# 设置日志功能
logger = logging.getLogger('[PythonService]')
this_file = inspect.getfile(inspect.currentframe())
dirpath = os.path.abspath(os.path.dirname(this_file))
handler = logging.FileHandler(os.path.join(dirpath, "service.log"))
formatter = logging.Formatter('%(asctime)s %(name)-12s %(levelname)-8s %(message)s')
handler.setFormatter(formatter)
logger.addHandler(handler)
logger.setLevel(logging.INFO)
return logger
def SvcDoRun(self):
"""
实例化win32serviceutil.ServiceFramework的时候,windows系统会自动调用SvcDoRun方法,
这个函数的执行不可以结束,因为结束就代表服务停止。
所以当我们放自己的代码在SvcDoRun函数中执行的时候,必须确保该函数不退出,就需要用死循环
:return: None
"""
self.logger.info("服务即将启动...")
while self.isAlive:
self.logger.info("服务正在运行...")
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
result = sock.connect_ex(('127.0.0.1', 9900)) # 嗅探网址是否可以访问,成功返回0,出错返回错误码
if result != 0:
# Python3.8的asyncio改变了循环方式,因为这种方式在windows上不支持相应的add_reader APIs,
# 就会抛出NotImplementedError错误。
# 因此加入下面两行代码
if sys.platform == 'win32':
asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy())
s = HTTPServer(WSGIContainer(app))
s.listen(9900)
IOLoop.current().start()
time.sleep(8)
sock.close()
time.sleep(20)
def SvcStop(self):
"""
当停止服务的时候,系统会调用SvcStop函数,该函数通过设置标志位等方式让SvcDoRun函数退出,就是正常的停止服务。
win32event.SetEvent(self.hWaitStop) 通过事件退出
:return: None
"""
self.logger.info("服务即将关闭...")
self.ReportServiceStatus(win32service.SERVICE_STOP_PENDING) # 先告诉SCM停止这个过程
win32event.SetEvent(self.stop_event) # 设置事件
self.ReportServiceStatus(win32service.SERVICE_STOPPED) # 确保停止,也可不加
self.isAlive = False
if __name__ == '__main__':
print("接收到的参数为", sys.argv)
if len(sys.argv) == 1:
print("输入参数不正确!")
try:
evtsrc_dll = os.path.abspath(servicemanager.__file__)
servicemanager.PrepareToHostSingle(PythonService)
servicemanager.Initialize('PythonService', evtsrc_dll)
servicemanager.StartServiceCtrlDispatcher()
except Exception as details:
print("发生异常,信息如下:", details)
# 如果错误的状态码为1063,则输出使用信息
if details[0] == winerror.ERROR_FAILED_SERVICE_CONTROLLER_CONNECT:
win32serviceutil.usage()
else:
win32serviceutil.HandleCommandLine(PythonService) # 括号里必须与class类名一致
3.部署为Windows Service服务并且开机自启
常用的服务命令主要有以下几种,首先安装服务,其次运行服务,在服务列表里,看到服务正在运行。在安装的过程中可能存在无法启动的异常,需要在系统变量的path变量中新建C:\Python\Python310\lib\site-packages\pywin32_system32,然后重新安装,启动。在浏览器中访问127.0.0.1:9900,出现相关页面,即可进行下一步
# 1.安装服务
python PythonService.py install
# 2.以开机自启的方式安装服务
python PythonService.py --startup auto install
# 3.启动服务
python PythonService.py start
# 4.重启服务
python PythonService.py restart
# 5.停止服务
python PythonService.py stop
# 6.删除/卸载服务
python PythonService.py remove
4.安装Nginx
从相关网站下载window版本的Nginx压缩包,解压到指定目录,双击exe文件启动Nginx,此时访问127.0.0.1出现欢迎揭界面,代表Nginx运行成功。
5.配置Nginx
修改D:\nginx-1.22.1\conf目录下的nginx.conf文件,添加一句话即可,保存后重启Nginx,在浏览器中访问localhost出现flask项目视图,完成。
proxy_pass http://localhost:9900; # 加上这句
server {
listen 80;
server_name localhost;
#charset koi8-r;
#access_log logs/host.access.log main;
location / {
root html;
index index.html index.htm;
proxy_pass http://localhost:9900; # 加上这句
}
#error_page 404 /404.html;
# redirect server error pages to the static page /50x.html
#
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
# proxy the PHP scripts to Apache listening on 127.0.0.1:80
#
#location ~ \.php$ {
# proxy_pass http://127.0.0.1;
#}
# pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
#
#location ~ \.php$ {
# root html;
# fastcgi_pass 127.0.0.1:9000;
# fastcgi_index index.php;
# fastcgi_param SCRIPT_FILENAME /scripts$fastcgi_script_name;
# include fastcgi_params;
#}
# deny access to .htaccess files, if Apache's document root
# concurs with nginx's one
#
#location ~ /\.ht {
# deny all;
#}
}