zoukankan      html  css  js  c++  java
  • 结合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=" 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等结合使用。

  • 相关阅读:
    Log4Net 发布后不能用
    主机ping不通虚拟机
    c# Delegate 和 Events
    ADO.NET
    .NET Windows Service
    Linux 常用命令三 touch mkdir
    Linux 常用命令二 pwd cd
    Linux 常用命令一 ls
    python 面向对象六 动态添加方法 __slots__限制动态添加方法
    python 面向对象六 类属性和实例属性
  • 原文地址:https://www.cnblogs.com/wt11/p/9288605.html
Copyright © 2011-2022 走看看