结合manage.py,在flask项目中使用websocket模块--- flask-socketio

前言:

      - 为什么我要使用 flask-socketio模块,而不是flask-sockets?

      - 因为flask-socketio与前端流行的websocket库socketio语法类似,前后端交互容易理解,并且flask-socketio能非常容易得与flask项目结合。

效果预览:

    后端数字更改,自动推送到前端

1.安装 flask-socketio

pip install flask-socketio

2.项目结构

myproject/
|-- env/
    |-- <python虚拟环境>
|-- report/ <项目的模块名称>
|-- api_1/ <接口蓝图>
|-- __init__.py
|-- views.py |-- main/ <前端蓝图> |-- __init__.py |-- views.py <路由和视图函数文件> ----------------------------------> 要增加websocket相关代码 |-- forms.py <表单类文件, wtforms插件必须项> |-- templates <HTML模板> |-- static <静态文件夹>
|-- index.html <前端页面> ------------------------------------> 要增加websocket相关代码 |-- XXXXXX/ <其它蓝图> |-- __init__.py ----------------------------------------------------> 要增加websocket相关代码 |-- models.py <数据库模型文件> |-- migrations/ <数据库表关系文件夹,Flask-Migrate迁移数据库时使用> |-- config.py <项目的配置文件> |-- manage.py <用于启动程序以及其它程序任务> --------------------------------> 要增加websocket相关代码

3.修改代码

1) 修改 myproject/report/__init__.py

# encoding: utf-8

from flask import Flask
from flask_mail import Mail
from flask_moment import Moment
from flask_sqlalchemy import SQLAlchemy
from config import config
from flask_restful import Api
from flask_cors import CORS     # 解决跨域请求
from flask_jwt_extended import JWTManager
from flask_socketio import SocketIO  # 新添加的代码


mail = Mail()
moment = Moment()
db = SQLAlchemy()
api = Api()

async_mode = None     # 新添加的代码
socketio = SocketIO()   # 新添加的代码
from report.api_1.views import ServiceCheckApi, GetRecordData# 为了避免循环引用问题,在这里导入
# 初始化app


def app_create(config_name):
    app = Flask(__name__)

    app.config.from_object(config[config_name])
    config[config_name].init_app(app)

    mail.init_app(app)
    moment.init_app(app)
    db.init_app(app)
    jwt = JWTManager(app)

    # 路由和其他处理程序定义
    # 注册蓝图
    from .main import main as main_blueprint  # 从当前目录下面的main子目录中导入main对象
    app.register_blueprint(main_blueprint)
    api.add_resource(ServiceCheckApi, '/api/service_check')  # api与websocket无关
    api.add_resource(GetRecordData, '/api/get_data')
    # add_resource 函数使用指定的endpoint 将路由注册到框架上
    api.init_app(app)  # api初始化必须放在路由注册之后
    CORS(app)  # 跨域请求
    socketio.init_app(app=app, async_mode=async_mode)  # 新添加的代码


    return app

 

2) 修改 myproject/manage.py

# encoding: utf-8
import os
from flask_script import Manager
from report import app_create
from flask_migrate import Migrate, MigrateCommand
from report import db, socketio  # 新添加代码


app = app_create(os.getenv('FLASK_CONFIG') or 'default')  # 设置启动方式,可选:development、testing、production
manager = Manager(app)
migrate = Migrate(app, db)  # 使用Migrate将app与db关联


# 自定义命令 ,
# 在命令行使用: python manage.py runserver
# @manager.command
# def runserver():
#     print('running')


# 添加额外二级命令
# 第一种方式:自定义命令
# manager.add_command('db',DBmanager)  # 'db'是自定义的命令名字
# 在命令行使用: python manage.py db init  ,init是自定义的函数


# 第二种方式:数据迁移使用MigrateCommand中自带的命令(常用)
# 该模块中带有的命令的使用顺序(顺序不能乱):
# python manage.py db init
# python manage.py db migrate
# python manage.py db upgrade
manager.add_command('db', MigrateCommand)
manager.add_command('run', socketio.run(app=app, host='0.0.0.0', port=5000)) # 新加入的代码,重写manager的run命令


if __name__ == '__main__':
    manager.run()

3)修改 myproject/report/main/views.py

# encoding: utf-8

import re
import requests
from . import main
from flask import render_template,redirect, url_forfrom report import socketio
import time
from flask_socketio import emit # 新加入的代码
from threading import Lock
import random

# 新加入的代码-开始
thread = None
thread_lock = Lock()

def background_thread(users_to_json):
    """Example of how to send server generated events to clients."""
    while True:
        print(users_to_json)
        users_to_json = [{'name': '王腾' + str(random.randint(1, 100))}]
        socketio.sleep(0.5) # 每五秒发送一次
        socketio.emit('user_response', {'data': users_to_json}, namespace='/websocket/user_refresh')

@socketio.on('connect', namespace='/websocket/user_refresh')
def connect():
    """ 服务端自动发送通信请求 """
    global thread
    user_to_json = ''
    with thread_lock:
        if thread is None:
            thread = socketio.start_background_task(background_thread, (users_to_json, ))
    emit('server_response', {'data': '试图连接客户端!'})


@socketio.on('connect_event', namespace='/websocket/user_refresh')
def refresh_message(message):
    """ 服务端接受客户端发送的通信请求 """
    emit('server_response', {'data': message['data']})
# 新加入的代码-结束

@main.route('/', methods=['GET'])
def index():
    return render_template('index.html')

4)修改myproject/report/main/templats/index.html

需要注意到是:

 

server_response、
user_response、
connect、
connect_event 

这几个自定义事件在前后端的对应关系。emit是发送消息,on是接收消息

 

<!doctype html>
<html>
    <head>
        <meta charset="utf-8">
        <meta http-equiv="x-ua-compatible" content="ie=edge">
        <title>xxx</title>
        <meta name="description" content="">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <!-- 引入css文件  start-->
        <link href="https://cdn.bootcss.com/bootstrap/4.1.0/css/bootstrap.css" rel="stylesheet">
        <!-- 引入css文件  end-->
    </head>
    <body style="margin: 0 auto">
        <div class="container">
            <div class="row">
                <div style="margin-bottom: 5%" class="col-md-12 text-center head-title-font">
                    <button id="auto_num" class="btn btn-primary" style="width: 10%"></button>
                </div>
            </div>
        </div>
<script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.slim.js"></script>
<!-- 新添加代码  start -->
    <script src="https://cdn.bootcss.com/socket.io/2.1.1/socket.io.dev.js"></script>
    <script>
        var socket = io('http://127.0.0.1:5000/websocket/user_refresh');-------------------------->  后台接口
        socket.on('connect', function() { // 发送到服务器的通信内容
        socket.emit('connect_event', {data: '我已连接上服务端!'});
    });

    socket.on('server_response', function(msg) {
        //显示接受到的通信内容,包括服务器端直接发送的内容和反馈给客户端的内容
        console.log(msg);
    });
    socket.on('user_response', function(msg) {
        // 获取后端传过来的业务数据
        var obj = eval(msg.data[0]);
        console.log(obj);
        $("#auto_num").empty();
        $("#auto_num").append(obj['name']);

    });
    </script>
<!-- 新添加代码 end -->
    </body>
</html>

 4. 项目启动

在项目目录下,执行:

python manage.py runserver

或者与gunicorn、uWSGI等结合使用。

 

posted @ 2018-07-10 13:47  明天OoO你好  阅读(5154)  评论(5编辑  收藏  举报