current position:Home>[Web Development] Python implements a web server (Flask packaged and deployed online)

[Web Development] Python implements a web server (Flask packaged and deployed online)

2022-11-08 08:08:19Xiaomu who loves to read

基于Python的Web服务器系列相关文章编写如下:

  1. 【Web开发】Python实现Web服务器(Flask快速入门)
  2. 【Web开发】Python实现Web服务器(Flask案例测试)
  3. 【Web开发】Python实现Web服务器(Flask部署上线)
  4. 【Web开发】Python实现Web服务器(Tornado入门)
  5. 【Web开发】Python实现Web服务器(Tornado+flask+nginx)
  6. 【Web开发】Python实现Web服务器(FastAPI)
  7. 【Web开发】Python实现Web服务器(Bottle)
  8. 【Web开发】Python实现Web服务器(Django)
  9. 【Web开发】Python实现Web服务器(web2py)
  10. 【Web开发】Python实现Web服务器(Sanic)


在这里插入图片描述

1、简介

Web Programs are usually deployed in two ways:Traditional and cloud deployments.Traditional deployment refers to deploying programs using physical hosts or virtual hosts,You usually need one Linux Complete all deployment operations on the system;Cloud deployments use cloud platforms provided by other companies,These platforms set up the underlying services for you,包括 Web 服务器、数据库等等,You just need to upload the code and do some simple settings to complete the deployment.

2、虚拟环境virtualenv

  • 安装第三方包:
pip install virtualenv
pip install virtualenvwrapper-win
  • 创建并进入虚拟环境:
mkvirtualenv flask_env
workon
workon flask_env
pip install -r requirements.txt
deactivate

3、更换WSGI容器

  • WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead.
    在这里插入图片描述

虽然 Flask 提供了内置 Web 服务器,但是那种服务器是为开发打造的,达不到生产环境中需要的安全和效率,细心的同学会注意到,用 app.run() 或者 flask run 启动应用时,都会得到一句警告:Do not use the development server in a production environment.

那么在生产环境中,需要用生产专用 Web 服务器,比如 uWSGI、Gunicorn、Gevent 等等.
独立的WSGI容器:There are many popular servers availablePython编写,它们包含WSGIapplication and availableHTTP服务.
在这里插入图片描述
Web框架(Flask)和Web服务器(Nginx)之间的通信,需要一套双方都遵守的接口协议.而WSGI协议就是用来统一这两者的接口的(WSGI是为Python语言定义的Web服务器和Web应用程序或框架之间的一种简单而通用的接口)

3.1 waitress

安装waitress
FlaskThe service itself does not support concurrent testing,本身的TPS很低,Therefore, other tools need to be used to support concurrent testing.
waitress是Windows下基于python的一个框架,可以提高Flask的TPS.

waitress支持windows环境

WaitressIt is a pure product with production grade quality and high performancepython编写独立的WSGI服务器,它只依赖python标准库,不依赖任何第三方库. At the same time it can run on multiple platforms,比如windows、linux、unix等,支持http/1.0和http/1.1.

pip install waitress

在这里插入图片描述

from waitress import serve
from flask import Flask
app = Flask(__name__)

@app.route('/')
def hello_world():
   return 'Hello World,爱看书的小沐!'

if __name__ == '__main__':
    # app.run()
    # app.run(host="127.0.0.1", port="8080")
    # app.run(host='localhost', port=8080, threaded=False, processes=1)
    serve(app, host='0.0.0.0', port=8080)
waitress-serve --call 'flaskr:create_app'
## Serving on http://0.0.0.0:8080

3.2 gevent

https://pypi.org/project/gevent/
http://www.gevent.org/
https://github.com/gevent/gevent

gevent is a coroutine -based Python networking library that uses greenlet to provide a high-level synchronous API on top of the libev or libuv event loop.

安装gevent:
flaskDirect use in production environments is lacking in handling high concurrency or robustness,一般会配合WGSIContainers for production deployment.WSGI主要规定了Web服务器如何与Web应用程序进行通信,以及如何将WebApplications are chained together to process a request.

gevent支持windows环境

gevent是一个基于 libev的并发库.它为各种并发和网络相关的任务提供了整洁的API.
gevent:基于 libev 与 Greenlet 实现.不同于 Eventlet 的用 python 实现的 hub 调度,gevent通过 Cython 调用 libev to achieve an efficient event loop 调度循环.同时类似于 Event,gevent也有自己的 monkey_patch,在打了补丁后,完全可以使用 python Threading is a way to use coroutines without awareness,减少了开发成本.

pip install gevent
from gevent.pywsgi import WSGIServer
from flask import Flask
app = Flask(__name__)

@app.route('/')
def hello_world():
   return 'Hello World,爱看书的小沐!'

if __name__ == '__main__':
    # app.run()
    # app.run(host="127.0.0.1", port="8080")
    # app.run(host='localhost', port=8080, threaded=False, processes=1)
    # serve(app, host='127.0.0.1', port=80, threads=1)
    # serve(app, host='0.0.0.0', port=8080)
    WSGIServer(('127.0.0.1', 8080), app).serve_forever()

引入gevent WSGI Server ,Here you need to enable monkey patching.而且需要注意 把gevent 猴子补丁 有关geventimports are placed before imports of other libraries.

# gevent
from gevent import monkey
from gevent.pywsgi import WSGIServer
# Some people say that adding the following sentence will not block the request
monkey.patch_all()
# gevent end
from flask import Flask
app = Flask(__name__)

@app.route('/')
def index():
    # 测试阻塞url1时,url2是否能够访问
    time.sleep(3000)
    return 'Hello World1'
    
@app.route('/hello')
def hello():
    return 'Hello World2'
 
if __name__ == '__main__':
    # app.run(port=5000,host="127.0.0.1")
    http_server = WSGIServer(('127.0.0.1', int(5000)), app)
    http_server.serve_forever()

3.3 Gunicorn

https://gunicorn.org
https://github.com/benoitc/gunicorn

Gunicorn ‘Green Unicorn’ is a Python WSGI HTTP Server for UNIX. It’s a pre-fork worker model. The Gunicorn server is broadly compatible with various web frameworks, simply implemented, light on server resources, and fairly speedy.

在这里插入图片描述

Gunicorn和uWSGI是常用的WSGI容器,Gunicorn直接用命令启动,不需要编写配置文件,相对uWSGI要容易很多.

Gunicorn ‘Green Unicorn’ 是一个 UNIX 下的 WSGI HTTP 服务器,它是一个 移植自 Ruby 的 Unicorn 项目的 pre-fork worker 模型.它既支持 eventlet , 也支持 greenlet.

Gunicorn是一个unix上被广泛使用的高性能的Python WSGI UNIX HTTP Server.
和大多数的web框架兼容,并具有实现简单,轻量级,高性能等特点.

Gunicorn 是一个 Python 的 WSGI HTTP 服务器.它所在的位置通常是在反向代理(如 Nginx)或者 负载均衡(如 AWS ELB)和一个 web 应用(比如 Django 或者 Flask)之间.

目前Gunicorn只能运行在Linux环境中,不支持windows平台.

pip install flask
pip install gunicorn
pip show gunicorn

#Create a soft link
ln /usr/local/python3.7/bin/gunicorn /usr/bin/gunicorn
# 在hello.py所在的目录下
# -w 设置进程数
# -b 设置端口
# 默认使用的是8000 可以通过-b 127.0.0.1:5000 设置到5000或其他端口
gunicorn -w 4 hello:app
gunicorn -w 5 --threads=2  main:app
gunicorn -w 5 --thread=2 --worker-class=gthread main:app
gunicorn --worker-class=gevent --worker-connections=1000 -w 3 main:app
gunicorn -w 4 demo:app --worker-class sync
gunicorn -w 4 demo:app  -k sync
##The first concurrency method(workers 模式,又名 UNIX 进程模式)
#每个 worker It's all a load Python 应用程序的 UNIX 进程.worker 之间没有共享内存.
#建议的 workers 数量是 (2*CPU)+1.
#for a dual core(两个CPU)机器,5 is suggested worker 数量.
gunicorn --workers=5 main:app

##The second concurrency method(多线程)
#Gunicorn 还允许每个 worker 拥有多个线程.在这种场景下,Python 应用程序每个 worker 都会加载一次,同一个 worker 生成的每个线程共享相同的内存空间.
gunicorn --workers=5 --threads=2 main:app
or
gunicorn --workers=5 --threads=2 --worker-class=gthread main:app
#use quad core(4 个 CPU)machine and we want to use workers and multithreaded mode,我们可以使用 3 个 worker 和 3 threads to get the maximum value 9 的并发请求数量.
gunicorn --workers=3 --threads=3 main:app

##The third concurrency method(“伪线程”)
#有一些 Python 库比如(gevent 和 Asyncio)可以在 Python Enable multiple concurrency in .That is implemented based on coroutines“伪线程”.Gunicrn 允许通过设置对应的 worker 类来使用这些异步 Python 库.
#(2*CPU)+1 仍然是建议的workers 数量.因为我们仅有一核,我们将会使用 3 个worker.
#在这种情况下,最大的并发请求数量是 3000.(3 个 worker * 1000 个连接/worker)
gunicorn --worker-class=gevent --worker-connections=1000 --workers=3 main:app

Concurrency means simultaneous execution 2 one or more tasks,This probably means that only one of them is being processed,while others are on hold.
Parallelism means that two or more tasks are executing at the same time.
在 Python 中,Both threads and pseudo-threads are a form of concurrency,But not in parallel.但是 workers It is a series of methods based on concurrency or parallelism.

gunicorn + flask 简单示例

  • mytest.py:
from flask import Flask

app = Flask(__name__)

@app.route('/demo', methods=['GET'])
def demo():
    return "This is a gunicorn and flask demo."
gunicorn mytest:app
#or
gunicorn --workers=2 mytest:app
#or
gunicorn --workers=4 --bind=127.0.0.1:8000 mytest:app

3.4 uWsgi

uWSGI Also deploy Flask 的途径之一,Similar deployment methods exist nginx 、 lighttpd 和 cherokee .See other deployment paths for information FastCGI 和 独立 WSGI 容器 . 使用 uWSGI protocol to deploy WSGI A prerequisite for applying is that one is required uWSGI 服务器. uWSGI Both a protocol and a server.如果作为一个服务器,It can serve uWSGI 、 FastCGI 和 HTTP 协议.

uWSGI是一个全功能的HTTP服务器,实现了WSGI协议、uwsgi协议、http协议等.它要做的就是把HTTP协议转化成语言支持的网络协议.比如把HTTP协议转化成WSGI协议,让Python可以直接使用.

最流行的 uWSGI 服务器是 uwsgi.

有网友说Windows 10安装uWSGI不可行,不要浪费时间.

pip install uwsgi
启动:uwsgi --ini uwsgi.ini
重启:uwsgi --reload uwsgi.pid
停止:uwsgi --stop uwsgi.pid

uwsgi --version
uwsgi --python-versioin
uwsgi --http :9090 --wsgi-file run.py
# --http: 通过 http 可访问,绑定端口为 9090
# --wsgi-file:指定启动脚本
#The file name created is  start.ini
[uwsgi]
#uwsgi启动时,所使用的地址和端口(这个是http协议的)
http=0.0.0.0:8000
#指向网站目录
chdir=/Users/myProjects/test001
#python 启动程序文件
wsgi-file=app.py
#python 程序内用以启动的application 变量名
callable=app
#处理器数
processes=4
#线程数
threads=2

#Start the project directly from the command line
uwsgi --ini start.ini

#如果你执行了 ctrl + c command exited the command line,You will find that our project cannot be accessed,Because you exit the foreground running uwsgi 命令.
#Want to exit the current command line,to execute other commands,而 flask Apps can be accessed normally,Just add one more parameter -d 即可,如下:
uwsgi -d --ini start.ini

#mac、LinuxCheck out first uwsgi 的进行号
ps -ef|grep uwsgi

3.5 Twisted Web

Twisted Web 是一个 Twisted 自带的网络服务器,是一个成熟的、异步的、 事件驱动的网络库. Twisted Web 带有一个标准的 WSGI 容器,该容器可以使用 twistd 工具运行命令行来控制.
Twisted Web支持windows环境部署

pip install -i https://pypi.douban.com/simple/  twisted
  • flask_web.py:
from flask import Flask
app = Flask(__name__)

@app.route('/')
def index():
    return 'Hello World'
    
if __name__ == '__main__':
    app.run()

通过命令行执行:

twistd -n web --wsgi flask_web.app

或者通过bat文件执行:

  • flask_run.bat
set PYTHONPATH=.;venv/Lib;venv/Lib/site-packages
set PATH=%PATH%;venv/Scripts
twistd -n web --port tcp:8080 --wsgi run.app

3.6 Tornado+nginx

【Web开发】Python实现Web服务器(Tornado+flask+nginx)
https://blog.csdn.net/hhy321/article/details/125233806
Tornado+nginx支持windows环境部署

3.7 apache+mod_wsgi

首先需要安装apache和mod_wsgi,需要注意的是python版本,apache版本,mod_wsgi版本要匹配,不然会出问题.
apache+mod_wsgi支持windows环境部署

Apache下载网址:https://www.apachelounge.com/download/VC10/
https://www.apachehaus.com/downloads/httpd-2.4.54-o111s-x64-vs17.zip
https://www.apachelounge.com/download/VC10/binaries/httpd-2.4.23-win64.zip
在这里插入图片描述
mod-wsgi下载网址:https://www.lfd.uci.edu/~gohlke/pythonlibs/#mod_wsgi
在这里插入图片描述
将下载好的httpd和mod-wsgi压缩包解压,然后将mod-wsgi的pyd文件放在httpd的modules文件夹里,如下图所示.
在这里插入图片描述
在这里插入图片描述

Create a new test project foldertest,在里面新建test_flask.py.

  • test_flask.py
import json
from flask import Flask, request, jsonify,render_template
app = Flask(__name__)

tasks = [
    {
    
        'id': 1,
        'title': u'订阅 a 专栏',
        'description': u'专栏Link: https://www.a.com'
    },
    {
    
        'id': 2,
        'title': u'订阅 b 专栏',
        'description': u'专栏Link: https://www.b.com'
    }
]

@app.route('/test')
def hello_world():
    return 'Hello World,爱看书的小沐!'

@app.route("/")
def index():
    # return render_template("index.html")
    return jsonify({
    'tasks': 200})

@app.route('/api/v1.0/tasks', methods=['GET'])
def get_tasks():
    return jsonify({
    'tasks': tasks})
    
@app.route('/getdata')
def get_data():
    language = ['python', 'java', 'c', 'c++', 'c#', 'php']
    value = ['100', '150', '100', '90', '80', '90']
    return json.dumps({
    'language':language,'value':value},ensure_ascii=False) 

if __name__ == '__main__':
    app.run(host="0.0.0.0", port=8080)

在项目文件夹test里,新建文件myapp.wsgi

  • myapp.wsgi
    在这里插入图片描述

修改apache httpd的相关参数设置.
在这里插入图片描述
httpd.conf文件增加一行:

LoadModule wsgi_module modules/mod_wsgi.cp38-win_amd64.pyd

在这里插入图片描述
修改一下httpd.conf的第40行的SRVROOT的参数,不修改的话,运行可能报错:
在这里插入图片描述

httpd.confAdd a piece of code at the end of the file as follows:

<VirtualHost *:80>
     ServerAdmin "127.0.0.1"
     ServerName localhost:80
     DocumentRoot D:\0627\test
     <Directory D:\0627\test>
         Require all granted
     </Directory>
     WSGIScriptAlias / D:\0627\test\myapp.wsgi
 </VirtualHost>

在这里插入图片描述

然后执行Apache24\bin\httpd.exe,开启web服务.
在这里插入图片描述
最后浏览器访问:

http://127.0.0.1

在这里插入图片描述

http://127.0.0.1/test

在这里插入图片描述

http://127.0.0.1/getdata

在这里插入图片描述
If it goes wrongapache24的logs文件夹的error.logfile to see what's wrong with the output.
在这里插入图片描述

4、打包工具PyInstaller

https://pypi.org/project/pyinstaller/
https://pyinstaller.org/en/stable/

在这里插入图片描述

4.1 requirements.txt

pip 提供了导出依赖模块名录的功能,可以一并导出依赖名录:
• 将环境中依赖的外部模块名录导入到 requirements.txt 中

pip freeze > requirements.txt

由于 pip freeze 与 pip list 内容区别不大,所以,若想要用其作为工程依赖包列表,一定要配合 Python 虚拟环境 virtualenv 使用.
• 在服务器上依据 requirements.txt 安装应用依赖

pip install -r requirements.txt

我们要将 requirements.txt 作为项目代码的一部分.

4.2 安装

Python 默认并不包含 PyInstaller 模块,因此需要自行安装 PyInstaller 模块.
安装 PyInstaller 模块与安装其他 Python 模块一样,使用 pip 命令安装即可.

pip install pyinstaller

4.3 参数

常用参数如下:
-F:打包 Python A program is a single executable file
-D:打包 Python A program is a folder
-i:生成图标,只适用于 Windows 平台
-n:Specifies the name of the resulting file after packaging
-w:表示去掉控制台窗口,这在GUI界面时非常有用.
–add-data: 表示添加资源文件,参数为 “源地址;目标地址”

-h–help查看该模块的帮助信息
-F-onefile产生单个的可执行文件
-D–onedir产生一个目录(包含多个文件)作为可执行程序
-a–ascii不包含 Unicode 字符集支持
-d–debug产生 debug 版本的可执行文件
-w–windowed,–noconsolc指定程序运行时不显示命令行窗口(仅对 Windows 有效)
-c–nowindowed,–console指定使用命令行窗口运行程序(仅对 Windows 有效)
-o DIR–out=DIR指定 spec 文件的生成目录.如果没有指定,则默认使用当前目录来生成 spec 文件
-p DIR–path=DIR设置 Python 导入模块的路径(和设置 PYTHONPATH 环境变量的作用相似).也可使用路径分隔符(Windows 使用分号,Linux 使用冒号)来分隔多个路径
-n NAME–name=NAME指定项目(产生的 spec)名字.如果省略该选项,那么第一个脚本的主文件名将作为 spec 的名字
参数参数意义
-F --onefile1.打包单个文件,产生一个文件用于部署(默认),如果代码都写在一个.py文件时使用,项目有多个文件时不要使用.例:pyinstaller -F xxx.py,例:pyinstaller --onefile xxxx.py
-D --onedir1.打包多个文件,产生一个目录用于部署(默认),用于框架编写的代码打包.例:pyinstaller -D xxx.py(项目入口文件),例:pyinstaller --onedir xxx.py(项目入口文件)
–key=keys1.使用keys进行加密打包.例:pyinstaller --key=1234 -F xx.py
-K --tk1.在部署时包含 TCL/TK
-a --ascii1.不包含编码.在支持Unicode的python版本上默认包含所有的编码
-d --debug1.产生debug版本的可执行文件
-n name --name=name1.可选的项目(产生的spec的)名字name.2.第一个脚本的主文件名将作为spec的名字(默认).例:pyinstaller -F -n my_file_name xxx.py.例:pyinstaller -F --name=my_file_name xxx.py
-o dir – out=dir1.指定spec文件的生成目录dir.2.If not specified and the current directory isPyInstaller的根目录,会自动创建一个用于输出(spec和生成的可执行文件)的目录.3.If not specified, the current directory is notPyInstaller的根目录,则会输出到当前的目录下
-p dir --path=dir1.用来添加程序所用到的包的所在位置,设置导入路径(和使用pythonpath效果相似).2.可以用路径分割符(Windows使用分号,Linux使用冒号)分割,指定多个目录.也可以使用多个-p参数来设置多个导入路径,让Pyintaller自己去找程序需要的资源.
-w --windowed --noconsole1.表示去掉控制台窗口,使用Windows子系统执行,当程序启动的时候不会打开命令行(只对Windows有效).例:pyinstaller -c xxx.py.例:pyinstaller xxx.py --noconsole
-c --nowindowed --console1.表示打开控制台窗口,使用控制台子系统执行,当程序启动的时候会打开命令行(默认)(只对Windows有效).例:pyinstaller -c xxx.py.例:pyinstaller xxx.py --console
-i --icon=<file.ioc>1.将file.ico添加为可执行文件的资源,改变程序的图标(只对Windows系统有效).例:pyinstaller -F -i file.ico xxx.py.例:pyinstall -F --icon=<file.ioc> xxx.py --icon=<file.exe,n> 1.将file.exe的第n个图标添加为可执行文件的资源(只对Windows系统有效)
-v file --version=file1.将verfile作为可执行文件的版本资源(只对Windows系统有效)
-s --strip1.可执行文件和共享库将run through strip.注意Cygwin的strip往往使普通的win32 Dll无法使用
-X --upx1.如果有UPX安装(执行Configure.py时检测),会压缩执行文件(Windows系统中的DLL也会)(参见note)

4.4 示例

pyinstaller your_program.py
pyinstaller --add-data 'src/README.txt:.' myscript.py
Pyinstaller -F -w main.py
pyinstaller -F -w --add-data="xxxx.gif;." myapp.py
pyinstaller -F xxx.spec

#pyinstaller x.py --add-data="源地址;目标地址". windows以;分割,linux以:分割
#将 config 目录的所有文件打包到目标的 config 文件夹(不存在会自动创建)下
pyinstaller x.py --add-data ".\\config\\*;.\\config"

#可使用多次 --add-data
pyinstaller x.py  -n Demo2.0.3 --key !@)v -i "res\logo.ico"  
--add-data=".\*.txt;." --add-data=".\*.json;." --add-data="res\*.*;.\res" 
--add-data="dist\models\*.*;.\models"
  • 打包单个文件
# 1.执行命令
pyinstaller -F xxx.py
# 2.去生成的dist文件夹找xxx.exe运行
# 3.运行成功,xxx.exe则为可执行文件,删除其它文件
  • 打包多个文件
# 1.执行命令,xxx.py为程序入口文件
pyinstall -D xxx.py 
# 2.删除生成的bulid和dist文件夹,仅保留xxx.spec文件
# 3.修改xxx.spec文件,详见2.2.1
# 4.执行命令
pyinstaller -F xxx.spec
# 5.去dist文件夹下找xxx.exe文件
# 6.运行成功,删除临时文件目录build;dist目录为打包的结果,可执行文件和其它程序运行的关联文件都在这个目录下
  • 注意事项:
    (1)文件打包后过大?在程序中尽量不使用import xx;而是使用 from xx import xx.
    (2)编辑.spec文件路径相关.windows尽量使用绝对路径,用双斜杠\.linux路径/home/my_project/web.路径避免使用中文.
    (3)打包错误:ModuleNotFoundError: No module named ‘xxx’
    方法1:pyinstaller -D --hidden-import=“xxx” main.py
    方法2:在myapp.spec中配置hiddenimports=[‘xxx’]
    (4)打包.spec文件报错:RecursionError: maximum recursion depth exceeded
    在spec文件上添加递归深度的设置
    import sys
    sys.setrecursionlimit(5000)

  • 利用*.spec Packaging file configuration to achieve multi-file packaging

# -*- mode: python ; coding: utf-8 -*-
block_cipher = None
# Folders can be required,Resources are added to the package like this
# 资源文件、The code needs to be packaged together
added_files = [
           ('d:/demo/Libs', 'Libs' ),
           ('d:/demo/Script', 'Script' )
         ]
#Analysis为主入口文件
a = Analysis(['main.py'],
#his path
             pathex=['d:\\demo'],
             binaries=[],
             datas=added_files,
             hiddenimports=[],
             hookspath=[],
             runtime_hooks=[],
             excludes=[],
             win_no_prefer_redirects=False,
             win_private_assemblies=False,
             cipher=block_cipher,
             noarchive=False)
pyz = PYZ(a.pure, a.zipped_data,
             cipher=block_cipher)
exe = EXE(pyz,
          a.scripts,
          a.binaries,
          a.zipfiles,
          a.datas,
          [],
          # 打包程序的名字
          name='your_exe_name',
          debug=False,
          bootloader_ignore_signals=False,
          strip=False,
          upx=True,
          upx_exclude=[],
          runtime_tmpdir=None,
          console=True,
#图标的地址
icon='your.ico' )
# -*- mode: python ; coding: utf-8 -*-
block_cipher = pyi_crypto.PyiBlockCipher(key='[email protected])v')
 
a = Analysis(['x.py'],
             pathex=['D:\\Miniconda3\\envs\\cuda11\\Lib\\site-packages', 'D:\\project\\demo'],
             binaries=[],
             datas=[('.\\*.json', '.'), ('res\\*.*', '.\\res'), ('dist\\models\\*.*', '.\\models')],
             hiddenimports=[],
             hookspath=[],
             runtime_hooks=[],
             excludes=[],
             win_no_prefer_redirects=False,
             win_private_assemblies=False,
             cipher=block_cipher,
             noarchive=False)
pyz = PYZ(a.pure, a.zipped_data,
             cipher=block_cipher)
exe = EXE(pyz,
          a.scripts,
          [],
          exclude_binaries=True,
          name='Demo2.0.3',
          debug=False,
          bootloader_ignore_signals=False,
          strip=False,
          upx=True,
          console=False , icon='res\\logo.ico')
coll = COLLECT(exe,
               a.binaries,
               a.zipfiles,
               a.datas,
               strip=False,
               upx=True,
               upx_exclude=[],
               name='Demo2.0.3')

5、注册Windows服务

5.1 pyinstaller + nssm

  • (1)安装相关库
# 安装flask库
pip install flask

# 安装pyinstaller库
pip install pyinstaller
# or
pip install -i https://pypi.tuna.tsinghua.edu.cn/simple pyinstaller
  • (2)编写相关web逻辑

myapp.py:

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

from flask import Flask, request, jsonify
app = Flask(__name__)


@app.route('/')
def hello_world():
    return 'Hello World,爱看书的小沐!'


@app.route('/modelstatus', methods=['GET', 'POST'])
def train_status():
    if request.method == 'GET':
        return jsonify({
    'code': 200, 'status': 'false', 'msg': 'hello'})
    else:
        return jsonify({
    'code': 500, 'msg': '不支持该请求'})


if __name__ == '__main__':
    app.run(host="0.0.0.0", port=8080)
  • (3)执行flask服务打包
#pyinstaller -p venv\Lib\site-packages -F --icon=铅笔.ico myapp.py --noconsole
pyinstaller -F -p D:\0627\hello  myapp.py
参数名描述说明
-D生成one-folder的程序(默认)生成结果是一个目录,各种第三方依赖、资源和exe同时存储在该目录
-F生成one-file的程序生成结果是一个exe文件,所有的第三方依赖、资源和代码均被打包进该exe内
–specpath指定.spec文件的存储路径默认:当前目录
-n生成的.exe文件和.spec的文件名默认:用户脚本的名称,即main.py和main.spec
-p指定额外的import路径类似于使用PYTHONPATH 参见PYTHONPATH
-d执行生成的main.exe时,会输出pyi的一些log,有助于查错默认:不输出pyi的log
-c显示命令行窗口与-w相反,默认含有此参数
-w不显示命令行窗口编写GUI程序时使用此参数有用.
-i为main.exe指定图标pyinstaller -i beauty.ico main.py

在这里插入图片描述
在这里插入图片描述

  • (4)注册windows服务
    nssm是一个服务封装程序,它可以将普通exe程序封装成服务,使之像windows服务一样运行.同类型的工具还有微软自己的srvany,不过nssm更加简单易用,并且功能强大.

nssm应该在 Windows 2000 or higher.具体来说,支持 Windows 7、Windows 8 和Windows 10.Included in download 32 位和 64 位二进制文​​件.大多数时候在 64 位 Windows 上运行 32 The bit version should be safe,But in some cases you may find it doesn't work,您必须使用 64 位版本.Both versions are compiled from the same source code.If one works for you,就用那个.如果没有,请尝试另一个.

直接下载:

https://nssm.cc/release/nssm-2.24.zip

(1)服务安装

nssm install <servicename>
nssm install <servicename> <program>
nssm install <servicename> <program> [<arguments>]

默认情况下,The service's startup directory will be set to includeprogram. 安装服务后,The startup directory can be overridden.

nssm set <servicename> AppDirectory <path>

(2)服务移除

nssm remove
nssm remove <servicename>
nssm remove <servicename> confirm

(3)启动和停止服务

nssm start <servicename>
nssm stop <servicename>
nssm restart <servicename>

(4)查询服务状态

nssm status <servicename>

在cmd中进入nssm中的目录,Then make the command
nssm install myapp(自定义的服务名)
选择Application path按钮将pyinstaller打包后的exefile selection.
点击installer service按钮,则提示成功,此时去windowsYou can view the service in the service.

在这里插入图片描述
Start and stop our service as follows:
在这里插入图片描述
Task Manager to view the service status as follows:
在这里插入图片描述

5.2 pywin32

  • (1)安装相关库
pip install flask gevent pywin32
  • (2)编写代码
    myapp.py:
from flask import Flask, request, jsonify
app = Flask(__name__)


@app.route('/')
def hello_world():
    return 'Hello World,爱看书的小沐!'


@app.route('/modelstatus', methods=['GET', 'POST'])
def train_status():
    if request.method == 'GET':
        return jsonify({
    'code': 200, 'status': 'false', 'msg': 'hello'})
    else:
        return jsonify({
    'code': 500, 'msg': '不支持该请求'})

myservice.py:

import win32serviceutil
from gevent.pywsgi import WSGIServer
from myapp import app

class MyFlaskService(win32serviceutil.ServiceFramework):
    # 服务名
    _svc_name_ = "myservice_dtale"
    # 显示服务名
    _svc_display_name_ = "myservice_dtale"
    # 描述
    _svc_description_ = "myservice_dtale's description"

    def __init__(self, *args):
        super().__init__(*args)
        # host和ip绑定
        self.http_server = WSGIServer(('127.0.0.1', 9090), app)
        self.SvcStop = self.http_server.stop
        self.SvcDoRun = self.http_server.serve_forever

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

myserver.py:(另一个写法)

import win32serviceutil
import win32service
import win32event
import win32evtlogutil
import servicemanager
import socket

import os
import sys
sys.path.append(os.path.dirname(__name__))

# import dtale
# import pandas as pd
from gevent.pywsgi import WSGIServer
from myapp import app

class MyDTaleService (win32serviceutil.ServiceFramework):
    # 服务名
    _svc_name_ = "myservice_dtale"
    # 显示服务名
    _svc_display_name_ = "myservice_dtale"
    # 描述
    _svc_description_ = "myservice_dtale's description"
    
    def __init__(self, *args):
        super().__init__(*args)
        self.hWaitStop = win32event.CreateEvent(None,0,0,None)
        socket.setdefaulttimeout(5)
        self.stop_requested = False
        # create server
        self.http_server = WSGIServer(('127.0.0.1', 9090), app)

    def SvcStop(self):
        self.ReportServiceStatus(win32service.SERVICE_STOP_PENDING)
        win32event.SetEvent(self.hWaitStop)
        self.ReportServiceStatus(win32service.SERVICE_STOPPED)
        self.stop_requested = True
        # stop server
        self.http_server.stop()

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

    def main(self):
        # df = pd.DataFrame([dict(a=1,b=2,c=3), dict(a=123.732,b=1.414,c=3.1415)])
        # dtale.show(df, open_browser=False)
        
        self.http_server.serve_forever()

if __name__ == '__main__':
    win32serviceutil.HandleCommandLine(MyDTaleService)
  • (3)添加系统环境变量
# Note that environment variables should be added to the system environment variablesPath中,Do not add it to the user's environment variables
C:\Python38
C:\Python38\Scripts
#C:\Python38\Lib\site-packages\win32
C:\Python38\Lib\site-packages\pywin32_system32
  • (4)安装服务
服务安装
python myservice.py install
让服务自动启动
python myservice.py --startup auto install
启动服务
python myservice.py start
重启服务
python myservice.py restart
停止服务
python myservice.py stop
删除/卸载服务
python myservice.py remove

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

6、whl文件制作

wheel是pythonNew distribution standards,Designed to replace traditional onesegg,pip >=1.4versions are supportedwheel, 使用wheel作为你pythonRelease file for the library,有如下好处:

  • 纯Python和本机CInstallation of extension packages is faster
  • Avoid executing arbitrary code to install.(避免setup.py)
  • CThe installation of the extension is not requiredLinux,Windows或macOS上进行编译
  • Allows for better caching for testing and continuous integration
  • Created during installation.pyc文件,以确保它们与使用的Python解释器匹配
  • More consistent installation across platforms and machines

6.1 安装

pip wheel 使用要求: setuptools>=0.8 和 wheel
pip wheel 使用包 wheel 包提供的 bdist_wheel 这个 setuptools extension to build a single wheel

pip install wheel
pip install --upgrade setuptools

#or
python3 -m pip install --user --upgrade setuptools wheel

6.2 示例

准备文件如下:
在这里插入图片描述

在这里插入图片描述

init.py:

# -*- coding: utf-8 -*-
# __init__.py
from .myapp import *
from .myservice import *

setup.py:

# -*- coding: utf-8 -*-
# setup.py
from setuptools import setup, find_packages

setup(
    name='myApp',
    version='1.1',
    packages=find_packages(),
    author='tomcat',
    author_email='[email protected]',
    description='测试打包',
    url='http://www.baidu.com',
    classifiers=[
        "Programming Language :: Python :: 3",
        "License :: OSI Approved :: MIT License",
        "Operating System :: OS Independent",
    ],
    python_requires='>=3.6',
)

执行命令行命令wheel,生成whl文件.

python .\setup.py bdist_wheel
# or
python setup.py sdist bdist_wheel

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
另外还可以:pip wheel --wheel-dir=/root/whl ./

结语

如果您觉得该方法或代码有一点点用处,可以给作者点个赞,或打赏杯咖啡;╮( ̄▽ ̄)╭
如果您感觉方法或代码不咋地//(ㄒoㄒ)//,就在评论处留言,作者继续改进;o_O???
如果您需要相关功能的代码定制化开发,可以留言私信作者;(*◡‿◡)
感谢各位大佬童鞋们的支持!( ´ ▽´ )ノ ( ´ ▽´)っ!!!

copyright notice
author[Xiaomu who loves to read],Please bring the original link to reprint, thank you.
https://en.pythonmana.com/2022/312/202211080755335006.html

Random recommended