flask 使用 gevent-websocket + gunicorn 部署 (python 实时日志开发+部署)
1 我的falsk websocket 环境 pip install -r ******.txt
eventlet==0.24.1 flake8==3.8.4 Flask==0.11.1 Flask-Cors==3.0.10 Flask-Script==2.0.5 Flask-SocketIO==2.7.2 Flask-Sockets==0.2.1 gevent==20.6.2 gevent-websocket==0.10.1 gpg==1.13.1 greenlet==1.1.1 gunicorn==19.10.0 python-socketio==5.4.0 websockets==8.1 Werkzeug==1.0.0
2 python 后端代码
# -*- coding: utf-8 -*-
from flask import Flask,request,render_template,redirect,session
import uuid,datetime
import subprocess
import sys
from geventwebsocket.handler import WebSocketHandler
from gevent.pywsgi import WSGIServer
import json,os
from log.log import create_app, setup_log # 配置日志
from config.config import Config
import logging
from flask import Flask, views, render_template, send_file, request, session, current_app
app = create_app("development")
app.secret_key = ';lkjnfdidiclsjek'
from flask_cors import CORS # 跨域
cors = CORS(app, resources={r"/api/*": {"origins": "*"}})
from flask_sockets import Sockets
sockets = Sockets(app)
def log_path(modle):
return path_data.get(modle) # 返回日志路径
WEBSOCKET_DICT = {}
@app.route('/login',methods=['GET','POST'])
def login():
if request.method == 'GET':
return render_template('login.html')
else:
uid = str(uuid.uuid4())
session['user_info'] = {'id': uid, 'name': request.form.get('user')}
return 'w'
def _decode_data(byte_data: bytes):
"""
解码数据
:param byte_data: 待解码数据
:return: 解码字符串
"""
try:
return byte_data.decode('UTF-8')
except UnicodeDecodeError:
return byte_data.decode('GB18030')
@sockets.route('/message')
def message(ws):
# modle = request.args.get("modle", None)
# print('123',modle)
uid = str(uuid.uuid4())
# session['user_info'] = uid
# . 判断是否为Websocket请求,http不包含wsgi.websocket
# ws = request.environ.get('wsgi.websocket')
# print(ws)
if not ws:
return 'use websocket'
# 此处连接成功
print('ok',session,uid)
# session.clear()
current_user_id =uid # 自定义websocket发送对象
WEBSOCKET_DICT[current_user_id] = ws
while True:
# print(WEBSOCKET_DICT,'WEBSOCKET_DICT.values()')
# . 等待用户发送消息,并接受
try:
message = ws.receive() # 对应的模块密码数据
print(message,'message')
is_t,modle=is_password(message) # 验证密码
if not is_t:
print('密码错误')
return '密码错误'
path=log_path(modle)
# 关闭 mesaage = None
if not message:
del WEBSOCKET_DICT[current_user_id]
break
print("---------------")
for u_id,conn in WEBSOCKET_DICT.items():
# print(conn,'conn',uid)
if u_id==uid:
# print(conn)
print(path,'test')# 获取模块日志路径
# path='/tmp/echo_stdout.log'
# path='D:/zhongan/framework/myframework/logs/framework.log'
cmd='tail -f %s'%path
print('\033[1;32m************** START **************\033[0m',cmd)
p = subprocess.Popen(cmd, stdin=subprocess.PIPE, stderr=subprocess.PIPE,
stdout=subprocess.PIPE, universal_newlines=True, shell=True, bufsize=1)
# 实时输出
while True:
line = p.stdout.readline()
print(line, end='')
conn.send(line) # 发送前端
if subprocess.Popen.poll(p) == 0: # 判断子进程是否结束
break
return p.returncode
except Exception as e:
print(e)
return '完毕'
if __name__ == '__main__':
# 如果是http请求走app使用原有的wsgi处理,如果是websocket请求走WebSocketHandler处理
http_server = WSGIServer(('0.0.0.0',8000 ), app, handler_class=WebSocketHandler)
http_server.serve_forever()
3 前端代码 index.vue
<template>
<div>
<!-- <span>flask返回的数据{{modle}} -->
<!-- </span> -->
<br />
<div v-for="i in new_data">
{{ i }}
</div>
</div>
</template>
<script>
export default {
name : 'test',
data() {
return {
websock: null,
new_data:[],
pwd:this.$route.params.pwd
}
},
created() {
this.initWebSocket();
},
destroyed() {
this.websock.close() //离开路由之后断开websocket连接
},
methods: {
initWebSocket(){ //初始化weosocket
const wsuri = "ws://192.168:8000/message";
this.websock = new WebSocket(wsuri);
this.websock.onmessage = this.websocketonmessage;
this.websock.onopen = this.websocketonopen;
this.websock.onerror = this.websocketonerror;
this.websock.onclose = this.websocketclose;
},
websocketonopen(){ //连接建立之后执行send方法发送数据
this.websocketsend(this.pwd);
},
websocketonerror(){//连接建立失败重连
// this.initWebSocket();
// alert('not ok')
},
add(data){
let mes_data=[]
mes_data.push(data)
this.new_data=mes_data
console.log(this.new_data)
},
websocketonmessage(e){ //数据接收
this.new_data.push(e.data)
// this.add(e.data)
console.log(e)
},
websocketsend(Data){//数据发送
this.websock.send(Data);
},
websocketclose(e){ //关闭
console.log('断开连接',e);
alert('密码错误')
},
},
mounted() {
this.pwd=this.$route.params.pwd
},
}
</script>
4 部署方案 nginx 部署前端 websocket 做后端服务 (不代理方式)
conf文件夹下 nginx 配置
server {
listen 8080;
server_name ****;
root /usr/share/nginx/www/; # 静态文件
location / {
try_files $uri $uri/ @router;
}
location @router {
rewrite ^.*$ /index.html last;
}
}
使用 gunicorn 启动 指定用 gevent-websocket
5 部署后端服务 环境安装完成之后 4进程 nohup 异步启动
hohup gunicorn -k geventwebsocket.gunicorn.workers.GeventWebSocketWorker -w 4 -b 0.0.0.0:8000 manage:app &

浙公网安备 33010602011771号