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('33[1;32m************** START **************33[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 &

  

  

原文地址:https://www.cnblogs.com/zhangshijiezsj/p/15471185.html